//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
/**
 * @addtogroup FPDFAPI
 * @{
 */

/**
 * @file
 * @brief The basic PDF parser.
 */
//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FPDF_PARSER_
#define _FPDF_PARSER_

#ifndef _FX_BASIC_H_
#include "../fxcrt/fx_ext.h"
#endif

#ifndef _FPDF_OBJECTS_
#include "fpdf_objects.h"
#endif
//<<<+++OPENSOURCE_MUST_END

class CPDF_Document;
class IPDF_DocParser;
class CPDF_Parser;
class CPDF_SecurityHandler;
class CPDF_StandardSecurityHandler;
class CPDF_CryptoHandler;
class CPDF_Object;
class IFX_FileRead;
class CFDF_Document;
class CFDF_Parser;
class CFX_Font;
class CFX_AffineMatrix;
class CFX_FloatRect;
class CPDF_Point;
class CPDF_DocPageData;
class CPDF_DocRenderData;
class CPDF_ModuleMgr;
class CFX_DIBSource;

class CPDF_Font;
class CPDF_Image;
class CPDF_ColorSpace;
class CPDF_Pattern;
class CPDF_FontEncoding;
class CPDF_IccProfile;

class CFX_PrivateData;

//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
class CPDF_DocumentCache;

class CPDF_SizeAnalysis;
class CPDF_AttachmentAcc;

class CPDF_ProgressiveEncryptHandler;
class CPDF_StandardProgressiveEncryptHandler;

// Enable async parsing related feature
#if !defined(_FPDFAPI_MINI_)
	#define _FPDFAPI_ASYNC_PARSING_
#endif
//<<<+++OPENSOURCE_END
/**
 * @name PDF document permissions, according to PDF Reference, Table 3.20.
 * 1-2 bits must be zero, 7-8, 13-32 bits must be 1. 
 */
/*@{*/

/**
 * @brief bit 3.
 * - (Revision 2) Print the document.
 * - (Revision 3 or greater) Print the document (possibly not at the highest
 * quality level, depending on whether bit 12 is also set). 
 */
#define FPDFPERM_PRINT			0x0004
/**
 * @brief bit 4. Modify the contents of the document by operations other than 
 * those controlled by bits 6, 9, and 11.
 */
#define FPDFPERM_MODIFY			0x0008
/**
 * @brief bit 5.
 * - (Revision 2) Copy or otherwise extract text and graphics from the 
 * document, including extracting text and graphics (in support of accessibility
 * to users with disabilities or for other purposes).
 * - (Revision 3 or greater) Copy or otherwise extract text and graphics 
 * from the document by operations other than that controlled by bit 10.
 */
#define FPDFPERM_EXTRACT		0x0010
/**
 * @brief bit 6. Add or modify text annotations, fill in interactive form fields, and, 
 * if bit 4 is also set, create or modify interactive form fields (including signature fields).
 */
#define FPDFPERM_ANNOT_FORM		0x0020
/**
 * @brief bit 9. (Revision 3 or greater) Fill in existing interactive form fields (including signature fields),
 * even if bit 6 is clear. 
 */
#define FPDFPERM_FILL_FORM		0x0100
/**
 * @brief bit 10. (Revision 3 or greater) Extract text and graphics (in support of accessibility
 * to users with disabilities or for other purposes). 
 */
#define FPDFPERM_EXTRACT_ACCESS	0x0200
/**
 * @brief bit 11. (Revision 3 or greater) Assemble the document (insert, rotate, or delete pages
 * and create bookmarks or thumbnail images), even if bit 4 is clear. 
 */
#define FPDFPERM_ASSEMBLE		0x0400
/**
 * @brief bit 12. (Revision 3 or greater) Print the document to a representation from 
 * which a faithful digital copy of the PDF content could be generated. 
 * When this bit is clear (and bit 3 is set), printing is limited to a low-level
 * representation of the appearance, possibly of degraded quality. 
 * (See implementation note 25 in Appendix H.) 
 */
#define FPDFPERM_PRINT_HIGH		0x0800

/** 
 * @brief the maximum page count. This is checked the page count is greater than the value. 
 * If the page count greater than the value, The PDF file is invalidate.
 */
#define FPDF_PAGE_MAX_NUM		0xFFFFF

/*@}*/ 

/** @brief Page enumeration handler interface. */
class IPDF_EnumPageHandler
{
public:
	/**
	 * Enumerate page function for call back. Return TRUE if you want the enumeration to continue.
	 *
	 * @param[in] pPageDict		The page dictionary. 
	 * @return Non-zero means you want the enumeration to continue, otherwise want not.
	 */
	virtual FX_BOOL EnumPage(CPDF_Dictionary* pPageDict) = 0;
};


/**
 * @brief Class for a PDF document. Application can get a document object from a file parser,
 * or create a new document from scratch
 * CPDF_Document can store private data for different modules.
 */
class CPDF_Document : public CFX_PrivateData, public CPDF_IndirectObjects
{
public:
	/**
	 * Construct from a document parser.
	 *
	 * @param[in] pParser		The input document parser.
	 */
	CPDF_Document(IPDF_DocParser* pParser);
	/** Construct an empty document. */
	CPDF_Document();
	/** The destructor. */
	~CPDF_Document();

	/** Get the document parser. */
	IPDF_DocParser*			GetParser() const { return m_pParser; }

	/** Get root dictionary (document catalog dictionary). */
	CPDF_Dictionary*		GetRoot() const { return m_pRootDict; }

	/** Get document info dictionary. Could be NULL. */
	CPDF_Dictionary*		GetInfo() const { return m_pInfoDict; }

	/**
	 * Get ID strings of the document. Could be empty.
	 *
	 * @param[out] id1		It receives the first ID string of the document.
	 * @param[out] id2		It receives the second ID string of the document.
	 */
	void					GetID(CFX_ByteString& id1, CFX_ByteString& id2) const { id1 = m_ID1; id2 = m_ID2; }

	/** Get number of pages in this document. */
	int						GetPageCount() const;

	/**
	 * Get page dictionary of a specified page. Page index starts from zero for the first page.
	 *
	 * @param[in] iPage		Specifies the zero-based index of the page in the document.
	 * @return The specified page dictionary.
	 */
	CPDF_Dictionary*		GetPage(int iPage);

	/**
	 * Get the page index from a indirect object number.
	 *
	 * @param[in] objnum	The input indirect object number.
	 * @return The zero-based index of page in the document.
	 */
	int						GetPageIndex(FX_DWORD objnum);
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Change page index.
	 *
	 * @param[in] objnum	Indirect object number for a page.
	 * @param[in] newIndex	New page index.
	 * @return	The final page index.
	 */
	int						SetPageIndex(FX_DWORD objnum, int newIndex);
	//<<<+++OPENSOURCE_END
	/**
	 * Enumerate pages with user-supplied page enumeration handler.
	 *
	 * @param[in] pHandler	The user-supplied page enumeration handler.
	 */
	void					EnumPages(IPDF_EnumPageHandler* pHandler);

	/** Get the user permission of the document. */
	FX_DWORD				GetUserPermissions(FX_BOOL bCheckRevision = FALSE) const;
	/** Whether the user has the owner permission of the document. */
	FX_BOOL					IsOwner() const;

	/**
	 * @name Get module specific data.
	 */
	/*@{*/

	/** Get document-specific data for PAGE module. */
	CPDF_DocPageData*		GetPageData() { return GetValidatePageData(); }
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
#ifdef _FPDFAPI_MT_
	CFX_LockObject*			GetLockObject(FX_LPVOID pObject);
#endif
	void					RemoveFontFromPageData(CPDF_Dictionary* pObject, FX_BOOL bForce = FALSE);
	//<<<+++OPENSOURCE_END
	/** Clear document-specific data for PAGE module. */
	void					ClearPageData();
	/** Remove color space from PAGE module. */
	void					RemoveColorSpaceFromPageData(CPDF_Object* pObject);
	
	/** Get document-specific data for RENDER module. */
	CPDF_DocRenderData*		GetRenderData() { return GetValidateRenderData(); }
	/** Clear document-specific data for RENDER module. */
	void					ClearRenderData();
	/** Clear document-specific font data for RENDER module. */
	void					ClearRenderFont();

	/*@}*/ 

	/**
	 * Check if an indirect object is a form stream or not, without actually loading the object
	 * Return TRUE if determined, FALSE if unknown (the default implementation).
	 *
	 * @param[in] objnum	The input indirect object number.
	 * @param[out] bForm	It receive whether it's a form stream or not.
	 * @return Non-zero means determined, otherwise unknown.
	 */
	FX_BOOL					IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) const;

	/**
	 * @name Functions implemented in PAGE module. 
	 * Load cached resources.
	 */
	/*@{*/
	
	/**
	 * Load a font from font dictionary.
	 *
	 * @param[in] pFontDict		The input font dictionary.
	 * @return A PDF font.
	 */
	CPDF_Font*				LoadFont(CPDF_Dictionary* pFontDict);
	/**
	 * Find if a font is already loaded.
	 *
	 * @param[in] pFontDict		The input font dictionary.
	 * @return A PDF font object is alreay loaded, or NULL is not loaded.
	 */
	CPDF_Font*				FindFont(CPDF_Dictionary* pFontDict);
	/**
	 * Load a color space from a PDF object.
	 *
	 * @param[in] pCSObj		The input PDF object.
	 * @param[in] pResources	The current resource dictionary, used for default device CS
	 * @return A PDF color space.
	 */
	CPDF_ColorSpace*		LoadColorSpace(CPDF_Object* pCSObj, CPDF_Dictionary* pResources = NULL);
	/**
	 * Load a pattern from a PDF object.
	 *
	 * @param[in] pObj			The input PDF object.
	 * @param[in] bShading		Whether the pattern is a shading pattern or not.
	 * @return A PDF pattern.
	 */
	CPDF_Pattern*			LoadPattern(CPDF_Object* pObj, FX_BOOL bShading, const CFX_AffineMatrix* matrix = NULL);
	/**
	 * Load an image from a PDF object.
	 *
	 * @param[in] pObj			The input PDF object (must be indirect object).
	 * @return A PDF image.
	 */
	CPDF_Image*				LoadImageF(CPDF_Object* pObj);
	/**
	 * Load a PDF stream accessor from a PDF stream.
	 *
	 * @param[in] pStream		The input PDF stream.
	 * @return A PDF stream accessor. 
	 */
	CPDF_StreamAcc*			LoadFontFile(CPDF_Stream* pStream);
	/**
	 * Load an ICC profile from a PDF stream.
	 *
	 * @param[in] pStream		The input PDF stream.
	 * @param[in] nComponents	The components of the color space specified in ICC profile.
	 * @return An ICC profile.
	 */
	CPDF_IccProfile*		LoadIccProfile(CPDF_Stream* pStream, int nComponents);

	/*@}*/ 

	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * @name Functions implemented in EDIT module. 
	 */
	/*@{*/
	
	/**
	 * Set the root object number. must be called for an empty document.
	 *
	 * @param[in] RootObjNum	The input root object number.
	 */
	void					SetRootObjNum(int RootObjNum);
	/**
	 * Set the info object number. must be called for an empty document.
	 *
	 * @param[in] InfoObjNum	The input info object number.
	 */
	void					SetInfoObjNum(int InfoObjNum);
	/**
	 * Set the PDF file ID.
	 *
	 * @param[in] id1			The first file ID.
	 * @param[in] id2			The second file ID.
	 */
	void					SetID(const CFX_ByteString& id1, const CFX_ByteString& id2) { m_ID1 = id1; m_ID2 = id2; }
    //<<<+++OPENSOURCE_END
    

//<<<+++OPENSOURCE_MUST_BEGIN
#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
//<<<+++OPENSOURCE_MUST_END
    
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
#if defined(_FX_WINAPI_PARTITION_DESKTOP_)
//<<<+++OPENSOURCE_MUST_END
	/**
	 * Import a Windows font.
	 *
	 * @param[in] pLogFont			Points to a LOGFONT(WIN32) structure that defines the characteristics of the logical font. 
	 * @param[in] bVert				Whether the font is a vertical font or not.
	 * @param[in] bTranslateName	Whether we will do font name translating or not.
	 * @return A PDF font.
	 */
	CPDF_Font*				AddWindowsFont(LOGFONTA* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName = FALSE);
	CPDF_Font*				AddWindowsFont(LOGFONTW* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName = FALSE);
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
#endif
//<<<+++OPENSOURCE_MUST_END
    
//<<<+++OPENSOURCE_MUST_BEGIN
#endif
//<<<+++OPENSOURCE_MUST_END
    
    //<<<+++OPENSOURCE_MUST_BEGIN
#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
    CPDF_Font*              AddMacFont(CTFontRef pFont, FX_BOOL bVert, FX_BOOL bTranslateName = FALSE);
#endif
	//<<<+++OPENSOURCE_MUST_END
	/**
	 * Add a Type1 base-14 font.
	 *
	 * @param[in] font				The font name.
	 * @param[in] pEncoding			The font encoding.
	 * @return A PDF font.
	 */
	CPDF_Font*				AddStandardFont(const FX_CHAR* font, CPDF_FontEncoding* pEncoding);
	
	/**
	 * Add a PDF font from FXGE font.
	 *
	 * @param[in] CFX_Font*		The FXGE font.
	 * @param[in] charset		Charset ID, see FXFONT_xxx_CHARSET defines in fx_font.h 
	 * @param[in] bVert			Whether it's a vertical writing font. For CJK charsets only			
	 * @return A PDF font.
	 */
	CPDF_Font*				AddFont(CFX_Font* pFont, int charset, FX_BOOL bVert);

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Build a list of all resources of specified type in this document. On return,
	 * the ResObjList array contains pointers to CPDF_Object objects.
	 *
	 * @param[in] type				The name of specified type.
	 * @param[out] ResObjList		It will receive all resource objects of specified type in the document.
	 */
	void					BuildResourceList(const FX_CHAR* type, CFX_PtrArray& ResObjList);
    //<<<+++OPENSOURCE_END
    
	/** Create a new document. */
	void					CreateNewDoc();
	/**
	 * Create a new page. Returns the created page.
	 *
	 * @param[in] iPage				Specifies the zero-based index of page to be created.
	 * @return The created page dictionary.
	 */
	CPDF_Dictionary*		CreateNewPage(int iPage);
	/**
	 * Delete specified page.
	 *
	 * @param[in] iPage				Specifies the zero-based index of page to be deleted.
	 */
	void					DeletePage(int iPage);

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Acrobat often requires stream of dictionary members of an object to be indirect objects.
	 *
	 * @param[in] pObject				The input PDF object.
	 * @param[in] bConvertStream		Whether we will convert stream to indirect object or not.
	 * @param[in] bConvertDictionary	Whether we will convert dictionary to indirect object or not.
	 */
	void					ConvertIndirectObjects(CPDF_Object* pObject,
								FX_BOOL bConvertStream, FX_BOOL bConvertDictionary, CFX_PtrArray* pStack);

	/**
	 * Get a modifiable content stream for a page.
	 *
	 * @param[in] pPageDict			The input page dictionary.
	 * @return An modifiable content stream for the page.
	 */
	CPDF_Stream*			GetPageContentModify(CPDF_Dictionary* pPageDict);

	/*@}*/ 
	
	/**
	 * Quick search an pattern for specified page.
	 *
	 * @param[in] page_index		The zero-based page index to be searched.
	 * @param[in] pattern			The pattern to search.
	 * @param[in] bCaseSensitive	Whether the pattern matching is case sensitive.
	 * @return Non-zero means searched one successfully.
	 */
	FX_BOOL					QuickSearch(int page_index, FX_LPCWSTR pattern, FX_BOOL bCaseSensitive);

	/** Reload page list. This can be used when document is progressively downloaded. */
	void					ReloadPages();
	//<<<+++OPENSOURCE_END

	/** Internally used */
	void					LoadDoc();

	void					LoadAsynDoc(CPDF_Dictionary *pLinearized);
	void					LoadPages();

#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CPDF_DocumentCache*		GetDocumentCache();
	//<<<+++OPENSOURCE_END
#endif

protected:
	/** The root dictionary. */
	CPDF_Dictionary*		m_pRootDict;
	/** The info dictionary. */
	CPDF_Dictionary*		m_pInfoDict;
	/** The first file ID. */
	CFX_ByteString			m_ID1;
	/** The second file ID. */
	CFX_ByteString			m_ID2;
	
	/** Whether is the linearized PDF. */
	FX_BOOL					m_bLinearized;
	/** The linearized first page no. */
	FX_DWORD				m_dwFirstPageNo;
	/** The linearized first page object number. */
	FX_DWORD				m_dwFirstPageObjNum;

	/** Record object numbers for each page. 0 for unknown. Size of this array is always page count. */
	CFX_DWordArray			m_PageList;
	FXMT_LOCKOBJECT_DEFINE(m_lockObjPageList);

	/** Get the page count. */
	int						_GetPageCount() const;

	CPDF_Dictionary*		_FindPDFPage(CPDF_Dictionary* pPages, int iPage, int nPagesToGo, int level);
	int						_FindPageIndex(CPDF_Dictionary* pNode, FX_DWORD& skip_count, FX_DWORD objnum, int& index, int level = 0);
	FX_BOOL					IsContentUsedElsewhere(FX_DWORD objnum, CPDF_Dictionary* pPageDict);
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	void					GetCharStream(CFX_WideTextBuf& buf, CPDF_Dictionary* pFormDict, CPDF_Object* pContent);
	//<<<+++OPENSOURCE_END
	FX_BOOL					CheckOCGVisible(CPDF_Dictionary* pOCG, FX_BOOL bPrinting);

	FXMT_LOCKOBJECT_DEFINE(m_lockObjOCG);

	CPDF_DocPageData*		GetValidatePageData();
	CPDF_DocRenderData*		GetValidateRenderData();
    
	friend class			CPDF_Creator;
	friend class			CPDF_Parser;
	friend class			CPDF_DataAvail;
	friend class			CPDF_OCContext;

#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CPDF_DocumentCache*		m_pDocumentCache;
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * @name Data pointers for extended modules. 
	 */
	/*@{*/

	/** Document-specific data for PAGE module. */
	CPDF_DocPageData*		m_pDocPage;
	/** Document-specific data for RENDER module. */
	CPDF_DocRenderData*		m_pDocRender;

	FXMT_LOCKOBJECT_DEFINE(m_lockObjDocPage);
	FXMT_LOCKOBJECT_DEFINE(m_lockObjDocRender);
	/*@}*/ 
};

/**
 * @name Word type. 
 */
 /*@{*/

/** @brief EOF. */
#define PDFWORD_EOF			0
/** @brief Number. */
#define PDFWORD_NUMBER		1
/** @brief Text. */
#define PDFWORD_TEXT		2
/** @brief Delimiter. */
#define PDFWORD_DELIMITER	3
/** @brief Name. */
#define PDFWORD_NAME		4

/*@}*/ 

/**
 * @brief Parsing a fixed buffer. Inside the buffer, there are words separated by delimiters.
 * Typical usage of this class includes searching the appearance stream, or a CMap file.
 */
class CPDF_SimpleParser : public CFX_Object
{
public:
	/**
	 * Construct a simple parser from a buffer. The buffer must retain valid until parsing finished.
	 *
	 * @param[in] pData		The input buffer.
	 * @param[in] dwSize	The size in bytes of the buffer.
	 */
	CPDF_SimpleParser(FX_LPCBYTE pData, FX_DWORD dwSize);

	/**
	 * Construct a simple parser from string. The string must retain valid until parsing finished.
	 *
	 * @param[in] str		The input string.
	 */
	CPDF_SimpleParser(FX_BSTR str);

	/**
	 * Get next word. NOTE: the word will be returned in its original form, unescaped, un-decoded. 
	 * For example, it will recognize "(hello(there)! :\))" as a legimate PDF string constant, however it
	 * won't return the value "hello(there)! :)", instead, the original form "(hello(there)!:\))" is returned. 
	 * Likewise, names are always returned with the preceding "/".
	 */
	CFX_ByteStringC		GetWord();

	/**
	 * Search a token from the current position, when stopped, the current position will be immediately
	 * after the found token. If token not found, the parser will stop at end of the buffer, and return FALSE.
	 * NOTE: the token is searched without word delimination.
	 *
	 * @param[in] token		The token to be searched.
	 * @return Non-zero means found a token, otherwise not.
	 */
	FX_BOOL				SearchToken(FX_BSTR token);

	/**
	 * Search a word from the current position. The parser will stop immediately after the found word.
	 * If not found, the parser will stop at end of the buffer, and return FALSE.
	 *
	 * @param[in] token		The token to be skipped.
	 * @return Non-zero means skip a token, otherwise not.
	 */
	FX_BOOL				SkipWord(FX_BSTR token);

	/**
	 * Find a start token and an end token (compared word by word), get the position after the start token,
	 * and position before the end token.
	 *
	 * @param[in] start_token	The start token to be found.
	 * @param[in] end_token		The end token to be found.
	 * @param[out] start_pos	It receives the position after the start token.
	 * @param[out] end_pos		It receives the position before the end token.
	 * @return Non-zero means find one, otherwise not.
	 */
	FX_BOOL				FindTagPair(FX_BSTR start_token, FX_BSTR end_token, 
							FX_DWORD& start_pos, FX_DWORD& end_pos);

	/**
	 * Search from the current position for a parameter of a tag. This is often used for parsing simple PostScript style
	 * texts. For example, if you have a buffer like "/F1 12.5 Tf ...", and you search for param #1 of "Tf" token,
	 * the parser will first search for token "Tf", then go back one word, and stop at the parameter value "12.5".
	 *
	 * @param[in] token			The token to be searched.
	 * @param[in] nParams		Zero-based index of the parameters for the token.
	 * @return Non-zero means find successfully, otherwise not.
	 */
	FX_BOOL				FindTagParam(FX_BSTR token, int nParams);

	/** Get current position of the parser. */
	FX_DWORD			GetPos() { return m_dwCurPos; }

	/** Set current position. */
	void				SetPos(FX_DWORD pos) { ASSERT(pos <= m_dwSize); m_dwCurPos = pos; }

private:
	/**
	 * Parse a word from current position, and the current position will be immediately after this word.
	 *
	 * @param[out] pStart		It receives the start position of the word.
	 * @param[out] dwSize		It receives the size in bytes of the word.
	 * @param[out] type			It receives the type of the word.
	 */
	void				ParseWord(FX_LPCBYTE& pStart, FX_DWORD& dwSize, int& type);

	/** The fixed buffer. */
	FX_LPCBYTE			m_pData;
	/** The size in bytes of the fixed buffer. */
	FX_DWORD			m_dwSize;
	/** The current position during parsing. */
	FX_DWORD			m_dwCurPos;
};

/** @brief A complicated syntax parser for PDF. */
class CPDF_SyntaxParser : public CFX_Object
{
public:
	/** The constructor. */
	CPDF_SyntaxParser();
	/** The destructor. */
	~CPDF_SyntaxParser();

	/**
	 * Init he syntax parser.
	 *
	 * @param[in] pFileAccess		The stream access interface.
	 * @param[in] HeaderOffset		The PDF header offset in the stream.
	 */
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	void				InitParser(IFX_FileRead* pFileAccess, FX_DWORD HeaderOffset, CPDF_SizeAnalysis* pSizeAnalysis = NULL);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	void				InitParser(IFX_FileRead* pFileAccess, FX_DWORD HeaderOffset);
	//<<<+++OPENSOURCE_END
#endif

	/** Save current position. */
	FX_FILESIZE			SavePos()	{ return m_Pos; }
	/**
	 * Restore a new position.
	 *
	 * @param[in] pos				The new position to restore.
	 */
	void				RestorePos(FX_FILESIZE pos)	{ m_Pos = pos; }

	/**
	 * Parse a PDF object.
	 *
	 * @param[out] pObjList			An indirect object list.
	 * @param[in] objnum			The object number.
	 * @param[in] gennum			The object generation number.
	 * @param[in] pContext			The parser context.
	 * @return A PDF object.
	 */
	CPDF_Object*		GetObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, FX_DWORD gennum, int level, struct PARSE_CONTEXT* pContext = NULL, FX_BOOL bDecrypt = TRUE);
	
	/**
	 * Parse a PDF object by strict syntax.
	 *
	 * @param[out] pObjList			An indirect object list.
	 * @param[in] objnum			The object number.
	 * @param[in] gennum			The object generation number.
	 * @param[in] pContext			The parser context.
	 * @return A PDF object.
	 */
	CPDF_Object*		GetObjectByStrict(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, FX_DWORD gennum, int level, struct PARSE_CONTEXT* pContext = NULL);

	/** Parse a number. */
	int					GetDirectNum();
	/**
	 * Parse a object buffer.
	 *
	 * @param[in] objnum			The object number.
	 * @param[in] gennum			The object generation number.
	 */
	CFX_ByteString		GetString(FX_DWORD objnum, FX_DWORD gennum);
	/** Parse a name. */
	CFX_ByteString		GetName();
	/** Parse a keyword. */
	CFX_ByteString		GetKeyword();
	/**
	 * Read a binary buffer.
	 *
	 * @param[out] buffer			It will receive the read buffer.
	 * @param[in] size				The buffer size in bytes to read.
	 */
	void				GetBinary(FX_BYTE* buffer, FX_DWORD size);

	/** Skip to next line. */
	void				ToNextLine();
	/** Skip to next word. */
	void				ToNextWord();
	/**
	 * Search a word from current position.
	 *
	 * @param[in] word				The word to search.
	 * @param[in] bWholeWord		Whether we will do a whole-word matching.
	 * @param[in] bForward			Whether we search forward or backward.
	 * @param[in] limit				The max number of bytes to search.
	 * @return Non-zero means found one, otherwise not.
	 */
	FX_BOOL				SearchWord(FX_BSTR word, FX_BOOL bWholeWord, FX_BOOL bForward, FX_FILESIZE limit);
	/**
	 * Search words from current position.
	 *
	 * @param[in] words				The words to search.
	 * @param[in] bWholeWord		Whether we will do whole-word matching.
	 * @param[in] limit				The max number of bytes to search.
	 * @return The position of the words.
	 */
	int					SearchMultiWord(FX_BSTR words, FX_BOOL bWholeWord, FX_FILESIZE limit);
	/**
	 * Find a tag.
	 *
	 * @param[in] tag				The tag string.
	 * @param[in] limit				The max number of bytes to search.
	 * @return The position of the tag.
	 */
	FX_FILESIZE			FindTag(FX_BSTR tag, FX_FILESIZE limit);

	/**
	 * Set encrypt handler.
	 *
	 * @param[in] pCryptoHandler	The encrypt handler.
	 */
	void				SetEncrypt(CPDF_CryptoHandler* pCryptoHandler) { m_pCryptoHandler = pCryptoHandler; }
	/** Whether the document is encrypted. */
	FX_BOOL				IsEncrypted() { return m_pCryptoHandler != NULL; }

	/**
	 * Get a byte at specified position.
	 *
	 * @param[in] pos			The zero-based position in the stream.
	 * @param[out] ch			It will receives the read byte.
	 * @return Non-zero means read successfully, otherwise not.
	 */
	FX_BOOL				GetCharAt(FX_FILESIZE pos, FX_BYTE& ch);
	/**
	 * Read a buffer.
	 *
	 * @param[out] pBuf			It will receive the read buffer.
	 * @param[in] size			The size in bytes to read.
	 * @return Non-zero means read successfully, otherwise not.
	 */
	FX_BOOL				ReadBlock(FX_BYTE* pBuf, FX_DWORD size);

	/**
	 * Get next word.
	 *
	 * @param[out] bIsNumber	It will receive whether the next word is a number.	
	 * @return A word buffer.
	 */
	CFX_ByteString		GetNextWord(FX_BOOL& bIsNumber);

protected:
	/**
	 * Get next byte.
	 *
	 * @param[out] ch			It will receive the next byte.
	 * @return Non-zero means read successfully, otherwise not.
	 */
	virtual FX_BOOL				GetNextChar(FX_BYTE& ch);
	/**
	 * Get byte at backward position.
	 *
	 * @param[in] pos			The backward position offset from the stream end.
	 * @param[out] ch			It will receive the read byte.
	 * @return Non-zero means read successfully, otherwise not.
	 */
	FX_BOOL				GetCharAtBackward(FX_FILESIZE pos, FX_BYTE& ch);
	/** Read a word, and move the position correspondingly. */
	void				GetNextWord();
	/**
	 * Is there a whole word ?
	 *
	 * @param[in] startpos		The start position.
	 * @param[in] limit			The maximum valid position.
	 * @param[in] tag			The tag string.
	 * @param[in] taglen		The length of the tag string.
	 * @return Non-zero means a whole word, otherwise a corrupted word.
	 */
	FX_BOOL				IsWholeWord(FX_FILESIZE startpos, FX_FILESIZE limit, FX_LPCBYTE tag, FX_DWORD taglen);
	/** Read a string. */
	CFX_ByteString		ReadString();
	/** Read a hex string. */
	CFX_ByteString		ReadHexString();
	/**
	 * Read a stream.
	 *
	 * @param[in] pDict			The dictionary of the stream.
	 * @param[in] pContext		The parser context.
	 * @param[in] objnum		The stream object number.
	 * @param[in] gennum		The stream object generation number.
	 * @return A PDF stream.
	 */
	CPDF_Stream*		ReadStream(CPDF_Dictionary* pDict, PARSE_CONTEXT* pContext, FX_DWORD objnum, FX_DWORD gennum);
    
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Reload a stream.
	 *
	 * @param[in] pos			The position to reload.
	 * @param[out] pStream		The stream will receive the reload data.
	 */
	FX_BOOL				ReloadFileStream(CPDF_IndirectObjects* pObjList, FX_FILESIZE pos, CPDF_Stream* pStream);
    //<<<+++OPENSOURCE_END
    
	/** The current position. */
	FX_FILESIZE			m_Pos;
	/** Whether the stream is a file stream. */
	FX_BOOL				m_bFileStream;
	/** The meta-data object number. */
	int					m_MetadataObjnum;

	/** The stream access interface. */
	IFX_FileRead*		m_pFileAccess;
	/** The PDF header offset in the stream. */
	FX_DWORD			m_HeaderOffset;
	/** The total length of the stream. */
	FX_FILESIZE			m_FileLen;

	/** The cached stream buffer. */
	FX_BYTE*			m_pFileBuf;
	/** The size in bytes of the stream buffer. */
	FX_DWORD			m_BufSize;
	/** The stream buffer offset in the whole stream. */
	FX_FILESIZE			m_BufOffset;

	/** The encrypt handler. */
	CPDF_CryptoHandler*	m_pCryptoHandler;

	/** The word buffer. we assume the max size of word is 256. */
	FX_BYTE				m_WordBuffer[257];
	/** The current word size. */
	FX_DWORD			m_WordSize;
	/** Whether the current word is a number. */
	FX_BOOL				m_bIsNumber;
	/** The word start position. */
	FX_FILESIZE			m_dwWordPos;

	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CPDF_SizeAnalysis* m_pSizeAnalysis;
	//<<<+++OPENSOURCE_END

	FXMT_LOCKOBJECT_DEFINE(m_lockObjSyntax);
	friend class		CPDF_Parser;
	friend class		CPDF_DataAvail;
};

/**
 * @name Flags for parser context. 
 */
 /*@{*/

/** @brief Type only. */
#define PDFPARSE_TYPEONLY	1
/** @brief No stream. */
#define PDFPARSE_NOSTREAM	2

/*@}*/ 

/** @brief Parser context. */
struct PARSE_CONTEXT
{
	/** The flags for parser context. */
	FX_BOOL		m_Flags;
	/** The start position of the dictionary. */
	FX_FILESIZE	m_DictStart;
	/** The end position of the dictionary. */
	FX_FILESIZE	m_DictEnd;
	/** The start position of the data. */
	FX_FILESIZE	m_DataStart;
	/** The end position of the data. */
	FX_FILESIZE	m_DataEnd;
};

/** @brief The document parser interface. */
class IPDF_DocParser : public CFX_Object
{
public:
	/** Get the root object number. */
	virtual FX_DWORD	GetRootObjNum() = 0;
	/** Get the info object number. */
	virtual FX_DWORD	GetInfoObjNum() = 0;
	/**
	 * Parse an indirect object.
	 * @param[out] pObjList			An indirect object list.
	 * @param[in] objnum			The object number.
	 * @param[in] pContext			The parser context.
	 * @return A PDF indirect object.
	 */
	virtual CPDF_Object*	ParseIndirectObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, PARSE_CONTEXT* pContext = NULL) = 0;
	/** Get the last object number in the document. */
	virtual FX_DWORD	GetLastObjNum() = 0;

	/** Get the file ID array. */
	virtual CPDF_Array*	GetIDArray() = 0;
	/** Get the encryption dictionary. */
	virtual CPDF_Dictionary*	GetEncryptDict() = 0;
	/** Is the PDF document encrypted ? */
	FX_BOOL				IsEncrypted() { return GetEncryptDict() != NULL; }
	/** Get the user permissions. */
	virtual FX_DWORD	GetPermissions(FX_BOOL bCheckRevision = FALSE) = 0;
	/** Whether the user has the owner permission of the document. */
	virtual FX_BOOL		IsOwner() = 0;

	/**
	 * Check if an indirect object is a form stream or not, without actually loading the object
	 * Return TRUE if determined, FALSE if unknown (the default implementation).
	 *
	 * @param[in] objnum	The input indirect object number.
	 * @param[out] bForm	It receive whether it's a form stream or not.
	 * @return Non-zero means determined, otherwise unknown.
	 */
	virtual FX_BOOL		IsFormStream(FX_DWORD objnum, FX_BOOL& bForm) = 0;

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Delete an indirect object from the indirect object list.
	 *
	 * @param[in] objnum	The indirect object number.
	 */
	virtual void		DeleteIndirectObject(FX_DWORD objnum) = 0;
    
	/**
	 * Reload a PDF stream.
	 *
	 * @param[in,out] pStream The PDF stream to be reload; It will receives the reloaded PDF stream.
	 * @return Non-zero means reload successfully. 
	 */
	virtual FX_BOOL		ReloadFileStream(CPDF_Stream* pStream) = 0;
    //<<<+++OPENSOURCE_END
};
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
typedef struct _PDF_ObjectSize : public CFX_Object 
{
	_PDF_ObjectSize();
	FX_FILESIZE		m_offset;
	FX_DWORD		m_size;
} PDF_ObjectSize;
 
typedef struct _PDF_ObjectItem : public CFX_Object
{
	_PDF_ObjectItem();
	~_PDF_ObjectItem();

	PDF_ObjectSize				m_object;
	CFX_CMapByteStringToPtr		m_objectDictItem;
	FX_DWORD					m_contentSize;
	FX_FLOAT					m_fScale;
} PDF_ObjectItem;

class CPDF_SizeAnalysis : public CFX_Object
{
public:
	CPDF_SizeAnalysis();
	~CPDF_SizeAnalysis();

	FX_DWORD		GetObjectSize(CPDF_Object* pObj);
	FX_DWORD		GetContentSize(CPDF_Object* pObj);
	FX_DWORD		GetKeySize(CPDF_Dictionary* pDict, const CFX_ByteString key);
	FX_DWORD		GetXRefSize();
	void			Clear();

 	PDF_ObjectItem*	GetObjectItem(CPDF_Object* pObj);
	void			RemoveObjectItem(CPDF_Object* pObj);

	FX_FLOAT		SaveScale();
	void			RestoreScale(FX_FLOAT scale);
	FX_DWORD		ConvertUnitSize(FX_DWORD size, FX_FLOAT scale);

	FX_FLOAT		m_fScale;
	CFX_MapPtrToPtr	m_objectMap;
	FX_DWORD		m_dwXRefSize;
};
//<<<+++OPENSOURCE_END
/**
 * @name Reasons for PDF parsing failure: returned by CPDF_Paser::StartParse() function.. 
 */
 /*@{*/

/** @brief no error. */
#define PDFPARSE_ERROR_SUCCESS		0
/** @brief file error: not found or could not be opened. */
#define PDFPARSE_ERROR_FILE			1
/** @brief format error: not a PDF or corrupted. */
#define PDFPARSE_ERROR_FORMAT		2
/** @brief Invalid password. Please input again. */
#define PDFPARSE_ERROR_PASSWORD		3
/** @brief This document is encrypted by some unsupported security handler. */
#define PDFPARSE_ERROR_HANDLER		4
/** @brief This document is encrypted by digital certificate and current user doesn't have correct certificate. */ 
#define PDFPARSE_ERROR_CERT			5

/*@}*/ 

/** @brief The default implementation of PDF Parser */
class CPDF_Parser : public IPDF_DocParser
{
public:
	/** Construct an empty parser. */
	CPDF_Parser();
	/** The destructor. */
	~CPDF_Parser();

	/**
	 * Start parsing from a file, ANSIC version.
	 *
	 * @param[in] filename		The input file full path name(The length must less than 256).
	 * @param[in] bReParse		Whether we will do reparsing.
	 * @return The status of PDF parsing.
	 */
	FX_DWORD			StartParse(FX_LPCSTR filename, FX_BOOL bReParse = FALSE);
	/**
	 * Start parsing from a file, Unicode version.
	 *
	 * @param[in] filename		The input file full path name(The length must less than 256).
	 * @param[in] bReParse		Whether we will do reparsing.
	 * @return The status of PDF parsing.
	 */
	FX_DWORD			StartParse(FX_LPCWSTR filename, FX_BOOL bReParse = FALSE);
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Start parsing from memory block.
	 *
	 * @param[in] pData			The input memory block.
	 * @param[in] nSize			The size in bytes of the memory block.
	 * @param[in] bReParse		Whether we will do reparsing.
	 * @return The status of PDF parsing.
	 */
	FX_DWORD			StartParse(FX_LPCBYTE pData, FX_DWORD nSize, FX_BOOL bReParse = FALSE);
	//<<<+++OPENSOURCE_END

	/**
	 * Start parsing a custom file.
	 *
	 * @param[in] pFile			The stream access interface.
	 * @param[in] bReParse		Whether we will do reparsing.
	 * @param[in] bOwnFileRead	Whether CPDF_Parser takes ownership of the file read structure (by calling IFX_FileRead::Release() when parser cleans up)
	 * @return The status of PDF parsing.
	 */
	FX_DWORD			StartParse(IFX_FileRead* pFile, FX_BOOL bReParse = FALSE, FX_BOOL bOwnFileRead = TRUE);

	/**
	 * Close the parser, as well as the file. If reparsing is used, the document will be kept.
	 *
	 * @param[in] bReParse		Whether reparsing is used.
	 */
	void				CloseParser(FX_BOOL bReParse = FALSE);

	/** Get the use permissions. */
	virtual FX_DWORD	GetPermissions(FX_BOOL bCheckRevision = FALSE);
	/** Whether the user has the owner permission of the document. */
	virtual FX_BOOL		IsOwner();

	/**
	 * Set the password of standard encryption for the parser.
	 *
	 * @param[in] password		The input password string.
	 */
	void				SetPassword(const FX_CHAR* password) { m_Password = password; }
	/** Get the password. */
	CFX_ByteString		GetPassword() { return m_Password; }
	/** Get the security handler. */
	CPDF_SecurityHandler* GetSecurityHandler() { return m_pSecurityHandler; }
	/** Get the encrypt handler. */
	CPDF_CryptoHandler*	GetCryptoHandler() { return m_Syntax.m_pCryptoHandler; }
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	FX_DWORD			CheckEmbeddedSecurity(FX_BSTR name);
	//<<<+++OPENSOURCE_END
	/**
	 * A document may be secured with non-standard security handler, which don't use the
	 * Encrypt dictionary. Therefore, after the initial parse, the application should create a
	 * custom security handler and then set into the parser.
	 * In this case, encrypted object stream and non-encrypted metadata stream are not supported.
	 *
	 * @param[in] pSecurityHandler	The input security handler.
	 * @param[in] bForced			Force use the specified security handler to parse.
	 *								When the bForced is FALSE, the security handler will be destroyed by the parser.
	 *								If the bForced is TRUE, the security handler need be destroyed by user.
	 */
	void				SetSecurityHandler(CPDF_SecurityHandler* pSecurityHandler, FX_BOOL bForced = FALSE);
    
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
    /** 
     * Remove the non-standard security handler.
     */
    void                RemoveSecurityHandler();
    
    /** Get the count of the origin recipients. */
    FX_DWORD            CountOriginRecipient();
    /** Get the content of the origin recipient. */
    CFX_ByteString      GetOriginRecipient(FX_DWORD index);
    /** Get the contents of origin recipients. */
    CFX_ByteStringArray& GetOriginRecipients();

	/** Set the recipient content. */
	void				SetRecipient(CFX_ByteString bsRecipient);
	//<<<+++OPENSOURCE_END
	/** Get the recipient content. */
	CFX_ByteString		GetRecipient() {return m_bsRecipient;}

	/** Get the trailer dictionary. */
	CPDF_Dictionary*	GetTrailer() { return m_pTrailer; }
	/** Get the offset of last xref. */
	FX_FILESIZE			GetLastXRefOffset() { return m_LastXRefOffset; }
	/** Get the PDF document. */
	CPDF_Document*		GetDocument() { return m_pDocument; }

	CFX_ArrayTemplate<CPDF_Dictionary *> * GetOtherTrailers() {return &m_Trailers;}
	
	virtual FX_DWORD	GetRootObjNum();
	virtual FX_DWORD	GetInfoObjNum();
	virtual CPDF_Array*	GetIDArray();
	virtual CPDF_Dictionary*	GetEncryptDict() { return m_pEncryptDict; }
	virtual CPDF_Object*		ParseIndirectObject(CPDF_IndirectObjects* pObjList, FX_DWORD objnum, PARSE_CONTEXT* pContext = NULL);
	virtual FX_DWORD	GetLastObjNum();

	virtual FX_BOOL		IsFormStream(FX_DWORD objnum, FX_BOOL& bForm);
    
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	virtual FX_BOOL		ReloadFileStream(CPDF_Stream* pStream);    
	virtual void		DeleteIndirectObject(FX_DWORD objnum);
	void				EnableSizeAnalysis(FX_BOOL bEnable = TRUE) { m_bEnableSizeAnalysis = bEnable; }
	/** 
	 * Get the version's length of the file.
	 */
	void				GetLengthOfVersions(CFX_FileSizeArray &arrayLengths);
    //<<<+++OPENSOURCE_END
    
	/**
	 * Get offset of indirect object.
	 *
	 * @param[in] objnum	The indirect object number.
	 * @return The offset of the indirect object. For objects stored in object stream, this is the 
	 *		offset of the object stream.
	 */
	FX_FILESIZE			GetObjectOffset(FX_DWORD objnum);
	/**
	 * Get data size of indirect object.
	 *
	 * @param[in] objnum	The indirect object number.
	 * @return The data size, in bytes, of the indirect object. For objects stored in object stream, this is the 
	 *		data size of the object stream.
	 */
	FX_FILESIZE			GetObjectSize(FX_DWORD objnum);

	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CPDF_SizeAnalysis*	GetSizeAnalysis() {return m_pSizeAnalysis;}
	//<<<+++OPENSOURCE_END
	/**
	 * Get the generation number of indirect object.
	 *
	 * @param[in] objnum	The indirect object number.
	 * @return The generation number of the indirect object.
	 */
	int					GetObjectVersion(FX_DWORD objnum) { return m_ObjVersion[objnum]; }

	/**
	 * For faster file updating, we can get the binary form of an indirect object, then
	 * directly output to destination file. In this case we must call the following
	 * function to get the binary buffer. Caller must release the buffer using delete[].
	 * NOTE: this function can't be used when m_bVersionUpdated is TRUE.
	 *
	 * @param[in] objnum	The input indirect object number.
	 * @param[out] pBuffer	It will receive the binary buffer for the indirect object.
	 * @param[out] size		It will receive the size in bytes of the binary buffer.
	 */
	void				GetIndirectBinary(FX_DWORD objnum, FX_BYTE*& pBuffer, FX_DWORD& size);
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Get position information for a stream:\n
	 * - # Start position (just before "<<") and end position (just after ">>") of the stream's dictionary;
	 * - # Start position (first byte) and end position (just after the last byte) of the stream's data.
	 *
	 * @param[in] objnum		The input indirect object number.
	 * @param[out] dict_start	Start position of the stream's dictionary.
	 * @param[out] dict_end		End position of the stream's dictionary.
	 * @param[out] data_start	Start position of the stream's data.
	 * @param[out] data_end		End position of the stream's data.
	 * @return Non-zero means parse successfully, otherwise not.
	 */
	FX_BOOL				ParseStreamPos(FX_DWORD objnum, FX_FILESIZE& dict_start, FX_FILESIZE& dict_end,
							FX_FILESIZE& data_start, FX_FILESIZE& data_end);

	/** 
	 * Get the indirect objects in specify byte range.
	 * @note this function is bitwise search so very slow.
	 *
	 * @param[out] objNum		The indirect object's number.
	 * @param[out] objPos		The indirect object's start position.
	 * @param[in] dwPos			The start position.
	 * @param[in] dwLen			The length will be parsed.
	 * @param[in] pContext		The parse context.
	 * @return Non_zero means parse successfully, otherwise not.
	 */
	FX_BOOL				ParseIndirectObjectsAtRange(CFX_DWordArray &objNum, CFX_FileSizeArray &objPos, FX_FILESIZE dwPos, FX_FILESIZE dwLen, 
							PARSE_CONTEXT* pContext);
	//<<<+++OPENSOURCE_END
	/**
	 * Get the file stream option.
	 * 
	 * Loading stream content into memory will improve performance for frequent access,
	 * however, it will also consume a lot of memory space.
	 * Therefore, we provide an option to leave stream content on file system, and read them
	 * whenever we need them. If may reduce the performance a little bit, but greatly reduce
	 * the memory consumption, especially when the file is big.
	 */
	FX_BOOL				GetFileStreamOption() { return m_Syntax.m_bFileStream; }
	/**
	 * Set the file stream option.
	 *
	 * @see CPDF_Parser::GetFileStreamOption()
	 * @param[in] b		Whether the stream is a file stream.
	 */
	void				SetFileStreamOption(FX_BOOL b) { m_Syntax.m_bFileStream = b; }

	/** Get the stream access interface. */
	IFX_FileRead*		GetFileAccess() const { return m_Syntax.m_pFileAccess; }

	/** Get the file version. File version: 14 for 1.4, 15 for 1.5, ... */
	int					GetFileVersion() const { return m_FileVersion; }
	/** whether cross reference stream is used. */
	FX_BOOL				IsXRefStream() const { return m_bXRefStream; }

	CPDF_Object*		ParseIndirectObjectAt(CPDF_IndirectObjects* pObjList, FX_FILESIZE pos, FX_DWORD objnum, 
							struct PARSE_CONTEXT* pContext);

	/** Parse indirect object by strict object's syntax. */
	CPDF_Object*		ParseIndirectObjectAtByStrict(CPDF_IndirectObjects* pObjList, FX_FILESIZE pos, FX_DWORD objnum, 
							struct PARSE_CONTEXT* pContext, FX_FILESIZE *pResultPos);

#if defined(_FPDFAPI_ASYNC_PARSING_)// && !defined(_FPDFAPI_MINI_)
	/** 
	 * Asynchronous parsing a custom file.
	 *
	 * @param[in] pFile			The stream access interface.
	 * @param[in] bReParse		Whether we will do reparsing.
	 * @param[in] bOwnFileRead	Whether CPDF_Parser takes ownership of the file read structure (by calling IFX_FileRead::Release() when parser cleans up)
	 * @return The status of PDF parsing.
	 */
	FX_DWORD			StartAsynParse(IFX_FileRead* pFile, FX_BOOL bReParse = FALSE, FX_BOOL bOwnFileRead = TRUE);
#endif

	/** 
	 * Get the first page no.
	 */
	FX_DWORD			GetFirstPageNo() {return m_dwFirstPageNo;}

protected:
	/** The PDF document. */
	CPDF_Document*		m_pDocument;
	/** The syntax parser. */
	CPDF_SyntaxParser	m_Syntax;

	FX_BOOL				m_bOwnFileRead;

	CPDF_Object*		ParseDirect(CPDF_Object* pObj);

	/**
	 * Load from common cross-reference table.
	 *
	 * @param[in] pos		The start position to load.
	 * @return Non-zero means successful, otherwise failed.
	 */
	FX_BOOL				LoadAllCrossRefV4(FX_FILESIZE pos);
	/**
	 * Load from cross-reference streams.
	 *
	 * @param[in] pos		The start position to load.
	 * @return Non-zero means successful, otherwise failed.
	 */
	FX_BOOL				LoadAllCrossRefV5(FX_FILESIZE pos);
	/** Load V4 cross-reference table. */
	FX_BOOL				LoadCrossRefV4(FX_FILESIZE pos, FX_FILESIZE streampos, FX_BOOL bSkip, FX_BOOL bFirst);
	/** Load V5 cross-reference table. */
	FX_BOOL				LoadCrossRefV5(FX_FILESIZE pos, FX_FILESIZE& prev, FX_BOOL bMainXRef);
	/** Get PDF Trailer dictionary for PDF1.4 or later. */
	CPDF_Dictionary*	LoadTrailerV4();
	/** Rebuild the cross-reference table. */
	FX_BOOL				RebuildCrossRef();
	/** Set the encrypt handler. */
	FX_DWORD			SetEncryptHandler();
	/** Release the encrypt handler. */
	void				ReleaseEncryptHandler();
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
    /** Load the origin recipients. */
    void                LoadRecipients();
    //<<<+++OPENSOURCE_END

#if defined(_FPDFAPI_ASYNC_PARSING_)// && !defined(_FPDFAPI_MINI_)
	/** Load linearized common cross-reference table. */
	FX_BOOL				LoadLinearizedAllCrossRefV4(FX_FILESIZE pos, FX_DWORD dwObjCount);
	/** Load linearized V4 cross-reference table. */
	FX_BOOL				LoadLinearizedCrossRefV4(FX_FILESIZE pos, FX_DWORD dwObjCount);
	/** Load linearized V5 cross-reference table.*/
	FX_BOOL				LoadLinearizedAllCrossRefV5(FX_FILESIZE pos);
	/** Load linearize main cross-reference table. */
	FX_DWORD			LoadLinearizedMainXRefTable();
#endif

	/** The Object stream map. From object number to CPDF_Stream*. */
	CFX_MapPtrToPtr		m_ObjectStreamMap;
	/**
	 * Get object stream.
	 *
	 * @param[in] number	The object number.
	 * @return A stream accessor for the object stream.
	 */
	CPDF_StreamAcc*		GetObjectStream(FX_DWORD number);

#if defined(_FPDFAPI_ASYNC_PARSING_)// && !defined(_FPDFAPI_MINI_)
	/** Whether the file is linearized PDF file. */
	FX_BOOL				IsLinearizedFile(IFX_FileRead* pFileAccess, FX_DWORD offset);
#endif

	/**
	 * @name Cached parsing info.
	 */
	/*@{*/

	/** The file version. */
	int					m_FileVersion;
	/** The Trailer dictionary. */
	CPDF_Dictionary*	m_pTrailer;
	/** The encryption dictionary. */
	CPDF_Dictionary*	m_pEncryptDict;
	void SetEncryptDictionary(CPDF_Dictionary* pDict);

	/** The offset of the last xref. */
	FX_FILESIZE			m_LastXRefOffset;
	/** Whether the cross-reference stream is used. */
	FX_BOOL				m_bXRefStream;

	/*@}*/ 


	/** The security handler. */
	CPDF_SecurityHandler*	m_pSecurityHandler;
	/** Whether force use the external specified security handler. */
	FX_BOOL					m_bForceUseSecurityHandler;

	/** The external specified recipient content. */
	CFX_ByteString			m_bsRecipient;

	/** The file path. */
	CFX_ByteString		m_FilePath;
	/** The user password. */
	CFX_ByteString		m_Password;

	/** Offset indexed by object number Or object stream number for compressed objects (V5). */
	CFX_FileSizeArray	m_CrossRef;
	/** V5 type of all objects (0,1,2). 255 for object container. */
	CFX_ByteArray		m_V5Type;
	/** Sorted offset for all indirect objects. */
	CFX_FileSizeArray	m_SortedOffset;
	/** Version numbers indexed by object number. */
	CFX_WordArray		m_ObjVersion;

	CFX_ArrayTemplate<CPDF_Dictionary *>	m_Trailers;

	/**
	 * If some indirect objects in the parsed PDF have version number
	 * greater than zero, then the m_bVersionUpdated flag is TRUE.
	 * In this case, the creator should NOT use GetIndirectBinary shortcut.
	 */
	FX_BOOL				m_bVersionUpdated;

	/** The linearized dictionary. */
	CPDF_Object*		m_pLinearized;
	/** The linearized first page no. */
	FX_DWORD			m_dwFirstPageNo;
	/** The cross-reference table start object number. */
	FX_DWORD			m_dwXrefStartObjNum;

	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** The size analysis object. */
	CPDF_SizeAnalysis*	m_pSizeAnalysis;
	FX_BOOL				m_bEnableSizeAnalysis;
    
    /** The origin recipients. */
    CFX_ByteStringArray     m_recipients;
    
	//<<<+++OPENSOURCE_END

	friend class		CPDF_Creator;
	friend class		CPDF_DataAvail;
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	friend class		CPDF_AttachmentAcc;
	//<<<+++OPENSOURCE_END
};

#define FXCIPHER_NONE	0
#define FXCIPHER_RC4	1
#define FXCIPHER_AES	2
#define FXCIPHER_AES2   3

/**
 * @brief Abstract class for all security handlers, contains virtual functions to be implemented by derived classes.
 */
class CPDF_SecurityHandler : public CFX_Object
{
public:
	/** Destructor. The handler should destroy all resources here. */
	virtual ~CPDF_SecurityHandler() {}

	/**
	 * Initialization. The handler should typically keep record of parser pointer, and
	 * process data in the encryption dictionary.
	 *
	 * @param[in] pParser			The PDF parser.
	 * @param[in] pEncryptDict		The Encrypt dictionary.
	 * @return Non-zero means initializing successfully, otherwise failed.
	 */
	virtual FX_BOOL		OnInit(CPDF_Parser* pParser, CPDF_Dictionary* pEncryptDict) = 0;
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	virtual FX_BOOL		CheckEmbeddedSecurity(FX_BSTR name) { return TRUE; }
	//<<<+++OPENSOURCE_END
	/** Get permission settings of the document. */
	virtual FX_DWORD	GetPermissions() = 0;

	/** Check whether the current user is owner of the document. */
	virtual FX_BOOL		IsOwner() = 0;

	/**
	 * Get encryption information including standard algorithm and key.
	 *
	 * @param[out] cipher			Receives cipher identifier (FXCIPHER_NONE, FXCIPHER_RC4 or FXCIPHER_AES).
	 * @param[out] buffer			Receives a pointer to the key buffer.
	 * @param[out] keylen			Receives number of bytes in the key.
	 * @return TRUE if successful. FALSE if no standard key info is provided or failure.
	 */
	virtual FX_BOOL		GetCryptInfo(int& cipher, FX_LPCBYTE& buffer, int& keylen) = 0;
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	virtual FX_BOOL		GetCryptInfo(FX_BSTR name, int& cipher, FX_LPCBYTE& buffer, int& keylen);
	//<<<+++OPENSOURCE_END

	/** Check if document metadata needs to be encrypted. */
	virtual FX_BOOL		IsMetadataEncrypted() { return TRUE; }

	/**
	 * Create a crypto handler that can do the real encryption/decryption work.
	 * After creation, the caller should call CPDF_CryptoHandler::Init() to initialize the crypto handler.
	 */
	virtual CPDF_CryptoHandler*	CreateCryptoHandler() = 0;

	/**
	 * Create a crypto handler that can do the real encryption/decryption work.
	 * After creation, the SecuirtyHandler should save the CPDF_CryptoHandler and call CPDF_CryptoHandler::Init to initialize the crypto handler.
	 * And the caller must not Init or delete the crypto handler.
	 */
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	virtual CPDF_CryptoHandler* CreateCryptoHandler(FX_BSTR name);
	//<<<+++OPENSOURCE_END

	virtual CPDF_StandardSecurityHandler* GetStandardHandler() { return NULL; }
};

#define PDF_ENCRYPT_CONTENT				0
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
#define PDF_ENCRYPT_EMBEDDEDFILES		1
//<<<+++OPENSOURCE_END
/**
 * @brief An implementation class of CPDF_SecurityHandler interface, supporting standard password-based
 * PDF security.
 *
 * @todo Full crypt filter support: need to change the CPDF_SecurityHandler interface, allowing
 * specific filter for each object when encrypting/decrypting
 */
class CPDF_StandardSecurityHandler : public CPDF_SecurityHandler
{
public:
	CPDF_StandardSecurityHandler();
	/** Destructor. The handler should destroy all resources here. */
	virtual ~CPDF_StandardSecurityHandler();

	virtual FX_BOOL		OnInit(CPDF_Parser* pParser, CPDF_Dictionary* pEncryptDict);
	virtual FX_DWORD	GetPermissions();
	virtual FX_BOOL		IsOwner() { return m_bOwner; }
	virtual FX_BOOL		GetCryptInfo(int& cipher, FX_LPCBYTE& buffer, int& keylen);
	virtual FX_BOOL		IsMetadataEncrypted();
	virtual CPDF_CryptoHandler*	CreateCryptoHandler();
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	virtual FX_BOOL		CheckEmbeddedSecurity(FX_BSTR name);
	virtual FX_BOOL		GetCryptInfo(FX_BSTR name, int& cipher, FX_LPCBYTE& buffer, int& keylen);
	virtual CPDF_CryptoHandler*	CreateCryptoHandler(FX_BSTR name);
	//<<<+++OPENSOURCE_END
	virtual CPDF_StandardSecurityHandler* GetStandardHandler() { return this; }

	/**
	 * Setup an encrypt dictionary.
	 *
	 * @param[in] pEncryptDict		The Encrypt dictionary.
	 * @param[in] pIdArray			The file IDs.
	 * @param[in] user_pass			The user password pointer.
	 * @param[in] user_size			The length of the user password.
	 * @param[in] owner_pass		The owner password pointer.
	 * @param[in] owner_size		The length of the owner password.
	 * @param[in] type				The encrypt type, refer to PDF_ENCRYPT_XXX.
	 */
	void				OnCreate(CPDF_Dictionary* pEncryptDict, CPDF_Array* pIdArray, 
							FX_LPCBYTE user_pass, FX_DWORD user_size, 
							FX_LPCBYTE owner_pass, FX_DWORD owner_size, FX_DWORD type = PDF_ENCRYPT_CONTENT);

	/**
	 * Setup an encrypt dictionary, it only set user password
	 *
	 * @param[in] pEncryptDict		The Encrypt dictionary.
	 * @param[in] pIdArray			The file IDs.
	 * @param[in] user_pass			The user password pointer.
	 * @param[in] user_size			The length of the user password.
	 * @param[in] type				The encrypt type, refer to PDF_ENCRYPT_XXX.
	 */
	void				OnCreate(CPDF_Dictionary* pEncryptDict, CPDF_Array* pIdArray, 
							FX_LPCBYTE user_pass, FX_DWORD user_size, FX_DWORD type = PDF_ENCRYPT_CONTENT);
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Modify security permissions for Revision 5 and 6 handler (AES 256)
	 * @param[out] pEncryptDict		The Encrypt dictionary to be modified.
	 * @param[in] permissions		New permissions.
	 * @param[in] bEncryptMetadata	Whether encrypt metadata
	 */
	void				ModifyAES256Permissions(CPDF_Dictionary* pEncryptDict, FX_DWORD permissions,
							FX_BOOL bEncryptMetadata);

	/**
	 * Modify passwords for Revision 5 and 6 handler (AES 256)
	 * @param[out] pEncryptDict		The Encrypt dictionary to be modified.
	 * @param[in] user_pass			The user password pointer.
	 * @param[in] user_size			The length of the user password. -1 for user password not modified.
	 * @param[in] owner_pass		The owner password pointer.
	 * @param[in] owner_size		The length of the owner password.
	 */
	void				ModifyAES256Passwords(CPDF_Dictionary* pEncryptDict, FX_LPCBYTE user_pass, FX_DWORD user_size, 
							FX_LPCBYTE owner_pass, FX_DWORD owner_size);
	//<<<+++OPENSOURCE_END
	/**
	 * Get user password from an owner password.
	 *
	 * @param[in] owner_pass		The owner password pointer.
	 * @param[in] pass_size			The length of the owner password.
	 * @return The correspond user password for this standard security handler.
	 */
	CFX_ByteString		GetUserPassword(FX_LPCBYTE owner_pass, FX_DWORD pass_size);
	CFX_ByteString		GetUserPassword(FX_LPCBYTE owner_pass, FX_DWORD pass_size, FX_INT32 key_len);

	int					GetVersion() { return m_Version; }
	int					GetRevision() { return m_Revision; }

	/**
	 * Check whether the password is verified successfully.
	 *
	 * @param[in] password			The input password pointer.
	 * @param[in] pass_size			The size of the password. 
	 * @param[in] bOwner			Whether check the owner password
	 * @param[out] key				Pointer to key buffer to receive the encryption key. NULL for don't calculate the key.
	 * @return FALSE for invalid password, TRUE for password verified.
	 */
	int					CheckPassword(FX_LPCBYTE password, FX_DWORD pass_size, FX_BOOL bOwner, FX_LPBYTE key);
	int					CheckPassword(FX_LPCBYTE password, FX_DWORD pass_size, FX_BOOL bOwner, FX_LPBYTE key, int key_len);

private:
	/** Version: 1,2, or 4. */
	int					m_Version;
	/** Revision of the standard handler: 2, 3, or 4. */
	int					m_Revision;
	/** The PDF parser. */
	CPDF_Parser*		m_pParser;

	/** The Encrypt dictionary of the document. */
	CPDF_Dictionary*	m_pEncryptDict;

	/** Load the Encrypt dictionary. */
	FX_BOOL				LoadDict(CPDF_Dictionary* pEncryptDict);
	FX_BOOL				LoadDict(CPDF_Dictionary* pEncryptDict, FX_DWORD type, int& cipher, int& key_len);
	/**
	 * Check whether the password is the user password.
	 *
	 * @param[in] password				The input password pointer.
	 * @param[in] pass_size				The size of the password.
	 * @param[in] bIgnoreEncryptMeta	Whether the meta-data's encryption is ignored.
	 * @return Non-zero means it's a user password, otherwise not.
	 */
	FX_BOOL				CheckUserPassword(FX_LPCBYTE password, FX_DWORD pass_size, 
							FX_BOOL bIgnoreEncryptMeta, FX_LPBYTE key, FX_INT32 key_len);
	/**
	 * Check whether the password is the owner password.
	 *
	 * @param[in] password			The input password pointer.
	 * @param[in] pass_size			The size of the password.
	 * @return Non-zero means it's a owner password, otherwise not.
	 */
	FX_BOOL				CheckOwnerPassword(FX_LPCBYTE password, FX_DWORD pass_size, FX_LPBYTE key, FX_INT32 key_len);

	FX_BOOL				AES256_CheckPassword(FX_LPCBYTE password, FX_DWORD size, FX_BOOL bOwner, FX_LPBYTE key);
	void				AES256_SetPassword(CPDF_Dictionary* pEncryptDict, FX_LPCBYTE password, FX_DWORD size, FX_BOOL bOwner, FX_LPCBYTE key);
	void				AES256_SetPerms(CPDF_Dictionary* pEncryptDict, FX_DWORD permission, FX_BOOL bEncryptMetadata, FX_LPCBYTE key);

	void				OnCreate(CPDF_Dictionary* pEncryptDict, CPDF_Array* pIdArray, 
							FX_LPCBYTE user_pass, FX_DWORD user_size, 
							FX_LPCBYTE owner_pass, FX_DWORD owner_size, FX_BOOL bDefault, FX_DWORD type);

	FX_BOOL				CheckSecurity(FX_INT32 key_len);
	/** Whether the current user is owner of the document. */
	FX_BOOL				m_bOwner;
	/** The user permissions. */
	FX_DWORD			m_Permissions;

	/** The cryptography algorithm. #FXCIPHER_RC4, #FXCIPHER_AES, or #FXCIPHER_NONE. */
	int					m_Cipher;
	/** The key of the cryptography algorithm. */
	FX_BYTE				m_EncryptKey[32];
	/** The length of the key. */
	int					m_KeyLen;
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CFX_MapByteStringToPtr	m_CryptoHandlerMap;
	//<<<+++OPENSOURCE_END
};

/**
 * @brief Abstract class for PDF cryptographic operations (encryption and decryption).
 * This class works with security handler which provides algorithm and key info.
 */
class CPDF_CryptoHandler : public CFX_Object
{
public:
	/** The destructor. */
	virtual ~CPDF_CryptoHandler() {}

	/**
	 * Initialize the crypto handler with a security handler, and the encrypt dictionary data.
	 * This function can be optional if the implementation do initialization in other way.
	 *
	 * @param[in] pEncryptDict		The Encrypt dictionary.
	 * @param[in] pSecurityHandler	The security handler.
	 * @return Non-zero means success, otherwise failure.
	 */
	virtual FX_BOOL		Init(CPDF_Dictionary* pEncryptDict, CPDF_SecurityHandler* pSecurityHandler) = 0;

	/**
	 * Estimate size of decrypted data, from a source size.
	 * If implementation doesn't want to estimate, it can always return 0.
	 *
	 * @param[in] src_size			The input source size.
	 * @return The estimated size. 0 means the implementation doesn't want to estimate.
	 */
	virtual FX_DWORD	DecryptGetSize(FX_DWORD src_size) = 0;

	/**
	 * Start a decryption process. If decryption is for some indirect object, object number and generation
	 * number are provided.
	 * Implementation can create a context and return pointer to the context.
	 *
	 * @param[in] objnum		The indirect object number.
	 * @param[in] gennum		The indirect object generation number.
	 * @return A decrypt context.
	 */
	virtual FX_LPVOID	DecryptStart(FX_DWORD objnum, FX_DWORD gennum) = 0;

	/**
	 * Decrypt some source data in a stream.
	 * The "context" parameter is the same as returned by DecryptStart() function.
	 * Implementation should append the decrypted data (if any) to the dest_buf dynamic array.
	 * 
	 * @param[in] context		The decrypt context.
	 * @param[in] src_buf		The encrypted source data.
	 * @param[in] src_size		The size in bytes of the source data.
	 * @param[out] dest_buf		It appends the decrypted data to the end.
	 * @return Non-zero means success, otherwise failure. 
	 */
	virtual FX_BOOL		DecryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf) = 0;

	/**
	 * Finish a decryption process.
	 * If decryption context is used, implementation should destroy it.
	 * If there is any left-over data, they should be added to the destination buffer.
	 *
	 * @param[in] context		The decrypt context.
	 * @param[out] dest_buf		It appends the decrypted data to the end.
	 * @return Non-zero means success, otherwise failure. 
	 */
	virtual FX_BOOL		DecryptFinish(FX_LPVOID context, CFX_BinaryBuf& dest_buf) = 0;
	
	/**
	 * Get encrypted data size for a source data block.
	 * The returned size should equal to or be larger than the final encrypted data block.
	 *
	 * @param[in] objnum		The indirect object number.
	 * @param[in] version		The indirect object generation number.
	 * @param[in] src_buf		The source data block.
	 * @param[in] src_size		The size in bytes of the source data.
	 * @return The encrypted data size. It should equal to or be larger than the final encrypted data block.
	 */
	virtual FX_DWORD	EncryptGetSize(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size) = 0;

	/**
	 * Do the encryption process.
	 * Final encrypted data block should be output in the "dest_size" parameter.
	 *
	 * @param[in] objnum		The indirect object number.
	 * @param[in] version		The indirect object generation number.
	 * @param[in] src_buf		The source data block.
	 * @param[in] src_size		The size in bytes of the source data.
	 * @param[out] dest_buf		It receives the encrypted data.
	 * @param[out] dest_size	It receives the size in bytes of the encrypted data.
	 * @return Non-zero means success, otherwise failure.
	 */
	virtual FX_BOOL		EncryptContent(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size,
							FX_LPBYTE dest_buf, FX_DWORD& dest_size) = 0;

	/**
	 * A utility function to decrypt a byte string, implemented by base class.
	 *
	 * @param[in] objnum		The indirect object number.
	 * @param[in] version		The indirect object generation number.
	 * @param[in,out] str		Input a byte string and receive the decrypted string.
	 */
	void				Decrypt(FX_DWORD objnum, FX_DWORD version, CFX_ByteString& str);
};

/**
 * @brief A standard implementation of crypto handler, support the standard PDF encryption and decryption.
 */
class CPDF_StandardCryptoHandler : public CPDF_CryptoHandler
{
public:
	/** The constructor. */
	CPDF_StandardCryptoHandler();
	/** The destructor. */
	virtual ~CPDF_StandardCryptoHandler();

	/**
	 * Initialize a crypto handler.
	 * This crypto handler can be initialized without a security handler or encrypt dictionary.
	 *
	 * @param[in] cipher		The cryptography algorithm type.
	 * @param[in] key			The key.
	 * @param[in] keylen		The length of the key.
	 * @return Non-zero means success, otherwise failure.
	 */
	FX_BOOL				Init(int cipher, FX_LPCBYTE key, int keylen);

	virtual FX_BOOL		Init(CPDF_Dictionary* pEncryptDict, CPDF_SecurityHandler* pSecurityHandler);
	virtual FX_DWORD	DecryptGetSize(FX_DWORD src_size);
	virtual FX_LPVOID	DecryptStart(FX_DWORD objnum, FX_DWORD gennum);
	virtual FX_BOOL		DecryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf);
	virtual FX_BOOL		DecryptFinish(FX_LPVOID context, CFX_BinaryBuf& dest_buf);

	virtual FX_DWORD	EncryptGetSize(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size);
	virtual FX_BOOL		EncryptContent(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size,
							FX_LPBYTE dest_buf, FX_DWORD& dest_size);
protected:
	/**
	 * Crypt(Encrypt or Decrypt) a block data.
	 *
	 * @param[in] bEncrypt		Whether we will encrypt a block data.
	 * @param[in] objnum		The indirect object number.
	 * @param[in] gennum		The indirect object generation number.
	 * @param[in] src_buf		The source data.
	 * @param[in] src_size		The size in bytes of the source data.
	 * @param[out] dest_buf		It will receive the crypted data.
	 * @param[out] dest_size	It will receive the size in bytes of the crypted data.
	 */
	virtual void		CryptBlock(FX_BOOL bEncrypt, FX_DWORD objnum, FX_DWORD gennum, FX_LPCBYTE src_buf, FX_DWORD src_size,
								FX_LPBYTE dest_buf, FX_DWORD& dest_size);

	virtual FX_LPVOID	CryptStart(FX_DWORD objnum, FX_DWORD gennum, FX_BOOL bEncrypt);
	virtual FX_BOOL		CryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf, FX_BOOL bEncrypt);
	virtual FX_BOOL		CryptFinish(FX_LPVOID context, CFX_BinaryBuf& dest_buf, FX_BOOL bEncrypt);

	/** The Key. */
	FX_BYTE				m_EncryptKey[32];
	/** The size in bytes of the key. */
	int					m_KeyLen;
	/** The cryptography algorithm. #FXCIPHER_RC4, #FXCIPHER_AES, or #FXCIPHER_NONE. */
	int					m_Cipher;
	/** Context for AES algorithm. */
	FX_LPBYTE			m_pAESContext;
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	friend class CPDF_StandardProgressiveEncryptHandler;
//<<<+++OPENSOURCE_END	
};
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
class CPDF_EFFStandardCryptoHandler : public CPDF_StandardCryptoHandler
{
public:
	virtual ~CPDF_EFFStandardCryptoHandler(){}

	virtual FX_BOOL		Init(CPDF_Dictionary* pEncryptDict, CPDF_SecurityHandler* pSecurityHandler);

	void				SetName(FX_BSTR name) { m_Name = name; }
protected:
	virtual void		CryptBlock(FX_BOOL bEncrypt, FX_DWORD objnum, FX_DWORD gennum, FX_LPCBYTE src_buf, FX_DWORD src_size,
						FX_LPBYTE dest_buf, FX_DWORD& dest_size);

	virtual FX_LPVOID	CryptStart(FX_DWORD objnum, FX_DWORD gennum, FX_BOOL bEncrypt);

	CFX_ByteString		m_Name;
};

class CPDF_ProgressiveEncryptHandler : public CFX_Object
{
public:
	virtual ~CPDF_ProgressiveEncryptHandler(){}

	/**
	 * Get temp file, we will use memory if return null. It will be called after EncryptStart.
	 */
	virtual IFX_FileStream*		GetTempFile() = 0;
	virtual void				ReleaseTempFile(IFX_FileStream* pFile) = 0;

	virtual FX_BOOL				SetCryptoHandler(CPDF_CryptoHandler* pCryptoHandler) = 0;

	/**
	 * Get encrypted data size for a source data block.
	 * The returned size should equal to or be larger than the final encrypted data block.
	 *
	 * @param[in] objnum		The indirect object number.
	 * @param[in] version		The indirect object generation number.
	 * @param[in] src_buf		The source data block.
	 * @param[in] src_size		The size in bytes of the source data.
	 * @return The encrypted data size. It should equal to or be larger than the final encrypted data block.
	 */
	virtual FX_DWORD			EncryptGetSize(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size) = 0;

	/**
	 * Start a encryption process. If encryption is for some indirect object, object number and generation
	 * number are provided.
	 * Implementation can create a context and return pointer to the context.
	 *
	 * @param[in] objnum		The indirect object number.
	 * @param[in] version		The indirect object generation number.
	 * @param[in] raw_size		The raw size of stream.
	 * @param[in] bFlateEncode	Whether the source need to encode.
	 * @return A encrypt context.
	 */
	virtual FX_LPVOID			EncryptStart(FX_DWORD objnum, FX_DWORD version, FX_DWORD raw_size, FX_BOOL bFlateEncode) = 0;
	/**
	 * Encrypt some source data in a stream.
	 * The "context" parameter is the same as returned by EncryptStart() function.
	 * Implementation should append the decrypted data (if any) to the dest_buf dynamic array.
	 * 
	 * @param[in] context		The encryption context.
	 * @param[in] src_buf		The source data.
	 * @param[in] src_size		The size in bytes of the source data.
	 * @param[out] pDest		It appends the decrypted data to the end.
	 * @return Non-zero means success, otherwise failure. 
	 */
	virtual FX_BOOL				EncryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, IFX_FileStream* pDest) = 0;
	/**
	 * Finish a encryption process.
	 * If encryption context is used, implementation should destroy it.
	 * If there is any left-over data, they should be added to the destination buffer.
	 *
	 * @param[in] context		The encrypt context.
	 * @param[out] pDest		It appends the decrypted data to the end.
	 * @return Non-zero means success, otherwise failure. 
	 */
	virtual FX_BOOL				EncryptFinish(FX_LPVOID context, IFX_FileStream* pDest) = 0;

	/**
	 * Update the filer if encoded.
	 */
	virtual FX_BOOL				UpdateFilter(CPDF_Dictionary* pDict) = 0;
};

class CPDF_StandardProgressiveEncryptHandler : public CPDF_ProgressiveEncryptHandler
{
public:
	CPDF_StandardProgressiveEncryptHandler();
	virtual ~CPDF_StandardProgressiveEncryptHandler();

	virtual IFX_FileStream*		GetTempFile() = 0;
	virtual void				ReleaseTempFile(IFX_FileStream* pFile) = 0;

	virtual FX_BOOL				SetCryptoHandler(CPDF_CryptoHandler* pCryptoHandler);

	virtual FX_DWORD			EncryptGetSize(FX_DWORD objnum, FX_DWORD version, FX_LPCBYTE src_buf, FX_DWORD src_size);
	virtual FX_LPVOID			EncryptStart(FX_DWORD objnum, FX_DWORD version, FX_DWORD raw_size, FX_BOOL bFlateEncode);
	virtual FX_BOOL				EncryptStream(FX_LPVOID context, FX_LPCBYTE src_buf, FX_DWORD src_size, IFX_FileStream* pDest);
	virtual FX_BOOL				EncryptFinish(FX_LPVOID context, IFX_FileStream* pDest);
	virtual FX_BOOL				UpdateFilter(CPDF_Dictionary* pDict);
protected:
	CPDF_StandardCryptoHandler*	m_pCryptoHandler;
	FX_LPVOID					m_DeflateContext;
	CFX_BinaryBuf				m_DestBuf;
	FX_DWORD					m_RawSize;
	FX_DWORD					m_Objnum;
	FX_DWORD					m_Version;
	FX_BOOL						m_bFlateEncode;
	FX_LPBYTE					m_OutBuffer;
	FX_INT32					m_OutSize;
};
//<<<+++OPENSOURCE_END
/** @brief PDF point class. */
class CPDF_Point : public CFX_Object
{
public:
	/**
	 * Construct with x and y coordinates.
	 *
	 * @param[in] xx	The x-coordinate.
	 * @param[in] yy	The y-coordinate.
	 */
	CPDF_Point(FX_FLOAT xx, FX_FLOAT yy) { x = xx; y = yy; }

	/** The x-coordinate of the point. */
	FX_FLOAT			x;
	/** The y-coordinate of the point. */
	FX_FLOAT			y;
};

/**
 * @name For compatibility only.
 */
 /*@{*/

/** @brief PDF rectangle. */
#define CPDF_Rect		CFX_FloatRect
/** @brief PDF matrix. */
#define CPDF_Matrix		CFX_AffineMatrix

/*@}*/ 

/**
 * Decode a name from it lexical form, From a non-buffered name of lexical form.
 * 
 * @param[in] orig		The input non-buffered name of lexical form.
 * @return The decoded name.
 */
CFX_ByteString PDF_NameDecode(FX_BSTR orig);
/**
 * Decode a name from it lexical form, From a buffered name of lexical form.
 *
 * @param[in] orig		The input buffered name of lexical form.
 * @return The decoded name.
 */
CFX_ByteString PDF_NameDecode(const CFX_ByteString& orig);

/**
 * Encode a name to lexical form (to be used for output).
 *
 * @param[in] orig		The input name.
 * @return A lexical form of the name.
 */
CFX_ByteString PDF_NameEncode(const CFX_ByteString& orig);

/**
 * Return PDF formatted string (including () or <>).
 *
 * @param[in] src		The input string.
 * @param[in] bHex		Whether we will do hex-encoding.
 * @return The PDF formatted string.
 */
CFX_ByteString PDF_EncodeString(const CFX_ByteString& src, FX_BOOL bHex = FALSE);

/**
 * Decode PDF encoded text string into a Unicode encoded string.
 * If no char map specified, PDFDocEncoding is used.
 * From a byte string.
 *
 * @param[in] str		The input PDF encoded text string.
 * @param[in] pCharMap	The input character mapping.
 * @return A Unicode encoded string.
 */
CFX_WideString PDF_DecodeText(const CFX_ByteString& str, CFX_CharMap* pCharMap = NULL);
/**
 * Decode PDF encoded text string into a Unicode encoded string.
 * If no char map specified, PDFDocEncoding is used.
 * From a memory block.
 *
 * @param[in] pData		The input PDF encoded text buffer.
 * @param[in] size		The size in bytes of the buffer.
 * @param[in] pCharMap	The input character mapping.
 * @return A Unicode encoded string.
 */
CFX_WideString PDF_DecodeText(FX_LPCBYTE pData, FX_DWORD size, CFX_CharMap* pCharMap = NULL);

/**
 * Encode a Unicode text string (UTF-16LE) into PDF encoding.
 * If no char map specified, PDFDocEncoding is used.
 *
 * @param[in] pString	The input Unicode text string (UTF-16LE).
 * @param[in] len		The length of the input unicode string. -1 for zero-terminated Unicode string.
 * @param[in] pCharMap	The input character mapping.
 * @return The PDF encoded string.
 */
CFX_ByteString PDF_EncodeText(FX_LPCWSTR pString, int len = -1, CFX_CharMap* pCharMap = NULL);

/**
 * Return a float that's clipped between 0 and 1, as used by many PDF parameters.
 *
 * @param[in] f			The input floating number.
 * @return The number if it's between 0 and 1, 0 if the number is negative, 1 if the number if greater than 1.
 */
FX_FLOAT PDF_ClipFloat(FX_FLOAT f);

/**
 * @brief Class for a FDF (Form Data Format) document. The FDF document can be created from scratch, or
 * parsed from a file or memory block (by CFDF_Parser class).
 */
class CFDF_Document : public CPDF_IndirectObjects
{
public:
	/** Create a new FDF document. The root dictionary will also be created automatically. */
	static CFDF_Document*	CreateNewDoc();

	/**
	 * Load a FDF document from a file.
	 *
	 * @param[in] file_path		The input file full path.
	 * @return A FPDF document.
	 */
	static CFDF_Document*	ParseFile(FX_LPCSTR file_path);

	/**
	 * Load a FDF document from a file.
	 *
	 * @param[in] file_path		The input file full path.
	 * @return A FPDF document.
	 */
	static CFDF_Document*	ParseFile(FX_LPCWSTR file_path);

	/**
	 * Load a FDF document from a file stream.
	 *
	 * @param[in] pFile			Reading file stream object.
	 * @param[in] bOwnFile		Indicates whether should release pFile when destroy current FDF document object.
	 * @return A FPDF document.
	 */
	static CFDF_Document*	ParseFile(IFX_FileRead *pFile, FX_BOOL bOwnFile = FALSE);

	/**
	 * Load a FDF document from a memory block.
	 *
	 * @param[in] pData			The input memory block.
	 * @param[in] size			The size in bytes of the block.
	 * @return A FPDF document.
	 */
	static CFDF_Document*	ParseMemory(FX_LPCBYTE pData, FX_DWORD size);

	/** The destructor. */
	~CFDF_Document();

	/**
	 * Write the content of this FDF document to a file.
	 *
	 * @param[in] file_path		The file full path to write to.
	 * @return Non-zero means success, otherwise failure.
	 */
	FX_BOOL					WriteFile(FX_LPCSTR file_path) const;

	/**
	 * Write the content of this FDF document to a file.
	 *
	 * @param[in] file_path		The file full path to write to.
	 * @return Non-zero means success, otherwise failure.
	 */
	FX_BOOL					WriteFile(FX_LPCWSTR file_path) const;

	/**
	 * Write the content of this FDF document to a file stream object.
	 *
	 * @param[in] pFile		The file stream object to write to.
	 * @return Non-zero means success, otherwise failure.
	 */
	FX_BOOL					WriteFile(IFX_FileWrite *pFile) const;

	/**
	 * Write the content of this FDF document to a memory block.
	 *
	 * @param[out] buf			It will receive the content of this PDF document.
	 * @return Non-zero means success, otherwise failure.
	 */
	FX_BOOL					WriteBuf(CFX_ByteTextBuf& buf) const;

	/** Get root dictionary of the FDF document. All other data can be fetched from this root. */
	CPDF_Dictionary*		GetRoot() const { return m_pRootDict; }

	/** Get file path of attached PDF document, if any. Different platform has different format. */
	CFX_WideString			GetWin32Path() const;

protected:
	/** The destructor. This object can't be constructed directly. */
	CFDF_Document();

	void	ParseStream(IFX_FileRead *pFile, FX_BOOL bOwnFile);

	CPDF_Dictionary*		m_pRootDict;
	IFX_FileRead*			m_pFile;
	FX_BOOL					m_bOwnFile;
};

/**
 * @name File specification utilities.
 */
 /*@{*/

/**
 * Get Win32 path from a PDF object.
 *
 * @param[in] pFileSpec		The input PDF object.
 * @return A Win32 path.
 */
CFX_WideString	FPDF_FileSpec_GetWin32Path(const CPDF_Object* pFileSpec);
/**
 * Set Win32 path to a PDF object.
 *
 * @param[out] pFileSpec	The output PDF object.
 * @param[in] fullpath		The input full path.
 */
void			FPDF_FileSpec_SetWin32Path(CPDF_Object* pFileSpec, const CFX_WideString& fullpath);

/*@}*/ 

/**
 * @name Encoding and decoding routines.
 */
 /*@{*/

/**
 * Flate encode algorithm.
 *
 * @param[in] src_buf		The source data.
 * @param[in] src_size		The size in bytes of the source data.
 * @param[out] dest_buf		It will receive the encoded data.
 * @param[out] dest_size	It will receive the size in bytes of the encoded data.
 */
void FlateEncode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);

/**
 * Flate decode algorithm.
 *
 * @param[in] src_buf		The source encoded data.
 * @param[in] src_size		The size in bytes of the source encoded data.
 * @param[out] dest_buf		It will receive the decoded data.
 * @param[out] dest_size	It will receive the size in bytes of the decoded data.
 * @return The size in bytes of source data consumed.
 */
FX_DWORD FlateDecode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);

/**
 * Run-length decode algorithm.
 *
 * @param[in] src_buf		The source encoded data.
 * @param[in] src_size		The size in bytes of the source encoded data.
 * @param[out] dest_buf		It will receive the decoded data.
 * @param[out] dest_size	It will receive the size in bytes of the decoded data.
 * @return The size in bytes of source data consumed.
 */
FX_DWORD RunLengthDecode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);

//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/**
 * Run-length encode algorithm.
 *
 * @param[in] src_buf		The source data.
 * @param[in] src_size		The size in bytes of the source data.
 * @param[out] dest_buf		It will receive the encoded data.
 * @param[out] dest_size	It will receive the size in bytes of the encoded data.
 */
void RunLengthEncode(const FX_BYTE* src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
//<<<+++OPENSOURCE_END
/*@}*/

/** @brief Number tree class, PDF common data structure. */
class CPDF_NumberTree : public CFX_Object
{
public:
	/**
	 * Construct from a dictionary of root number tree node.
	 *
	 * @param[in] pRoot		The input root number tree.
	 */
	CPDF_NumberTree(CPDF_Dictionary* pRoot) { m_pRoot = pRoot; }

	/**
	 * Lookup a PDF object identified by number.
	 *
	 * @param[in] num		The input number.
	 * @return A PDF object.
	 */
	CPDF_Object*		LookupValue(int num);

protected:
	/** The dictionary of root number tree node. */
	CPDF_Dictionary*	m_pRoot;
};

/**
 * @name Asynchronous file accessing.
 */
 /*@{*/

/** @brief File availability interface. */
class IFX_FileAvail
{
public:
	/**
	 * Determine whether the specified data section is available. It's available only all data in the section is available. 
	 *
	 * @param[in] offset	The input data offset in file.
	 * @param[in] size		The input data size.
	 * @return	TRUE means the specified data section is available.
	 */
	virtual FX_BOOL			IsDataAvail( FX_FILESIZE offset, FX_DWORD size) = 0;
};

/** @brief Download hints interface. Used if there are some data sections that are not available, so needed to feedback the hints. */
class IFX_DownloadHints
{
public:
	/**
	 * Add a section. The position and size of section may be not accurate, e.g. The beginning part has already been downloaded possibly,
	 * or the middle part is always downloaded. The downloading manager must deal with tht details.
	 *
	 * @param[in] offset	The data offset to be hinted.
	 * @param[in] size		The data size.
	 */
	virtual void			AddSegment(FX_FILESIZE offset, FX_DWORD size) = 0;
};

/** @brief The result of the process which check linearized PDF. */
#define PDF_IS_LINEARIZED			1
#define PDF_NOT_LINEARIZED			0
#define PDF_UNKNOW_LINEARIZED		-1

/** @brief The result of the form download status. */
#define PDFFORM_NOTAVAIL		0
#define PDFFORM_AVAIL			1
#define PDFFORM_NOTEXIST		2

/** @brief PDF data availability interface. */
class IPDF_DataAvail
{
public:
	/**
	 * Check whether the cross reference table and page tree root is available, add downloading sections to hints if not available.
	 * Application may create CPDF_Parser and get the CPDF_Document pointer after IPDF_DataAvailability::IsDocAvail() returns TRUE.
	 *
	 * @param[in] pHints	The download hints to be added to.
	 * @return TRUE means the document data is available.
	 */
	virtual FX_BOOL			IsDocAvail(IFX_DownloadHints* pHints) = 0;
	
	/**
	 * Pass in the document pointer, then we can access the information of every indirect objects, and also to determine which
	 * indirect objects are depended.
	 *
	 * @param[in] pDoc		The input document pointer. 
	 */
	virtual void			SetDocument(CPDF_Document* pDoc) = 0;
		
	/**
	 * Check whether the page is available, add downloading sections to hints if not available.
	 * Application may calls page functions like LoadPage etc after IPDF_DataAvailability::IsPageAvail() returns TRUE.
	 * NOTE: It must be called after IPDF_DataAvailability::IsDocAvail() returns TRUE. 
	 * 
	 * @param[in] iPage		The input zero-based page index.
	 * @param[in] pHints	The download hints to be added to.
	 * @return TRUE means the page data is available.
	 */
	virtual FX_BOOL			IsPageAvail(int iPage, IFX_DownloadHints* pHints) = 0;

	/** 
	 * Whether the document is Linearized PDF file.
	 * Add this function is order to quickly display the first page of the linearized file.
	 * It must be called after IPDF_DataAvailability::IsDocAvail(). When this function return TRUE, 
	 * application must calls IPDF_DataAvailability::GetLinearizedMainXRefInfo(). 
	 *
	 * @return TRUE means the document is linearized PDF else not.
	 */
	virtual FX_BOOL			IsLinearized() = 0;

	/** 
	 * Check whether the form is available, add downloading sections to hints if not available.
	 * NOTE: It must be called after the start parse document and before the Page available.
	 *
	 * @return	PDFFORM_NOTAVAIL means the form data is not available.
	 *			PDFFORM_AVAIL means the form data is available.
	 *			PDFFORM_NOTEXIST means the form is not exist.
	 */
	virtual FX_INT32		IsFormAvail(IFX_DownloadHints *pHints) = 0;

	/** 
	 * Check whether the PDF file is linearized file.
	 * 
	 * @return The state.	PDF_IS_LINEARIZED is a linearize file.
	 *						PDF_NOT_LINEARIZED is not a linearize file.
	 *						PDF_UNKNOW_LINEARIZED don't know whether the file is a linearize file.
	 */
	virtual FX_INT32		IsLinearizedPDF() = 0;

	/** 
	 * Get the linearized main cross-reference table position and size.
	 * When the file is linearized file. First application should get the linearized main cross-reference table position and size.
	 * Then application may create a thread to download the segment's content. If this segment's content doesn't download.
	 * The application access the page index which is not the document start page index, the IPDF_DataAvailability::IsPageAvail() 
	 * will always return FALSE.
	 *
	 * @param[out] pPos			The main cross-reference table position.
	 * @param[out] pSize		The main cross-reference table size.
	 */
	virtual void				GetLinearizedMainXRefInfo(FX_FILESIZE *pPos, FX_DWORD *pSize) = 0;
};

class CPDF_SortObjNumArray : public CFX_Object
{
public:
	/** 
	 * Add the obj number.
	 */
	void AddObjNum(FX_DWORD dwObjNum);

	/** 
	 * Find the obj number.Whether the object's number is exist.
	 */
	FX_BOOL Find(FX_DWORD dwObjNum);

	/** 
	 * Remove all elements. 
	 */
	void RemoveAll() {m_number_array.RemoveAll();}

protected:
	/** 
	 * Binary search the specify object's number.
	 * 
	 * @param[in] value		The specify value.
	 * @param[out] iNext	If not found,the value is insert position;else the value is fount index.
	 * return TRUE means find.
	 */
	FX_BOOL BinarySearch(FX_DWORD value, int &iNext);

protected:
	/** The indirect object number array. */
	CFX_DWordArray			m_number_array;
};

/** @brief the page node item's type. */
enum PDF_PAGENODE_TYPE {
	PDF_PAGENODE_UNKOWN = 0,
	PDF_PAGENODE_PAGE,
	PDF_PAGENODE_PAGES,
	PDF_PAGENODE_ARRAY,
};

/** @brief the Page tree struct. */
class CPDF_PageNode : public CFX_Object
{
public:
	CPDF_PageNode() : m_type(PDF_PAGENODE_UNKOWN) {}
	~CPDF_PageNode();

	PDF_PAGENODE_TYPE	m_type;
	FX_DWORD			m_dwPageNo;
	CFX_PtrArray		m_childNode;
};

/** @brief the CPDF_DataAvail parse document status.*/
enum PDF_DATAAVAIL_STATUS {
	PDF_DATAAVAIL_HEADER = 0,
	PDF_DATAAVAIL_FIRSTPAGE,
	PDF_DATAAVAIL_FIRSTPAGE_PREPARE,	//Check the first page is prepared.
	PDF_DATAAVAIL_END,
	PDF_DATAAVAIL_CROSSREF,
	PDF_DATAAVAIL_CROSSREF_ITEM,		//Check the xref table item
	PDF_DATAAVAIL_CROSSREF_STREAM,		//Check the xref stream.
	PDF_DATAAVAIL_TRAILER,
	PDF_DATAAVAIL_LOADALLCRSOSSREF,
	PDF_DATAAVAIL_ROOT,
	PDF_DATAAVAIL_INFO,
	PDF_DATAAVAIL_ACROFORM,
	PDF_DATAAVAIL_ACROFORM_SUBOBJECT,
	PDF_DATAAVAIL_PAGETREE,
	PDF_DATAAVAIL_PAGE,
	PDF_DATAAVAIL_PAGE_LATERLOAD,
	PDF_DATAAVAIL_RESOURCES,
	PDF_DATAAVAIL_DONE,
	PDF_DATAAVAIL_ERROR,
	PDF_DATAAVAIL_LOADALLFILE,
	PDF_DATAAVAIL_TRAILER_APPEND	//This download trailer after 512 bytes.
};

/** @brief PDF data availability class. Used to determine whether the document and page data is available. */
class CPDF_DataAvail : public CFX_Object, public IPDF_DataAvail
{
public:
	/**
	 * Construct from both file access and file availability interface.
	 *
	 * @param[in] pFileAvail	The file availability pointer.
	 * @param[in] pFileRead		The file read pointer.
	 */
	CPDF_DataAvail(IFX_FileAvail* pFileAvail, IFX_FileRead* pFileRead);

	~CPDF_DataAvail();

	/**
	 * Check whether the cross reference table and page tree root is available, add downloading sections to hints if not available.
	 * Application may create CPDF_Parser and get the CPDF_Document pointer after IPDF_DataAvailability::IsDocAvail() returns TRUE.
	 *
	 * NOTE: Not implemented.
	 *
	 * @param[in] pHints	The download hints to be added to.
	 * @return TRUE means the document data is available.
	 */
	virtual FX_BOOL				IsDocAvail(IFX_DownloadHints* pHints);
	
	/**
	 * Pass in the document pointer, then we can access the information of every indirect objects, and also to determine which
	 * indirect objects are depended.
	 *
	 * @param[in] pDoc		The input document pointer. 
	 */
	virtual void				SetDocument(CPDF_Document* pDoc);
	
	/**
	 * Check whether the page is available, add downloading sections to hints if not available.
	 * Application may calls page functions like LoadPage etc after IPDF_DataAvailability::IsPageAvail() returns TRUE.
	 * NOTE: It must be called after IPDF_DataAvailability::IsDocAvail() returns TRUE. 
	 * 
	 * @param[in]	iPage		The input zero-based page index.
	 * @param[in]	pHints		The download hints to be added to.
	 * @return TRUE means the page data is available.
	 */
	virtual FX_BOOL				IsPageAvail(int iPage, IFX_DownloadHints* pHints);

	/** 
	 * Check whether the form is available, add downloading sections to hints if not available.
	 * NOTE: It must be called after the start parse document and before the Page available.
	 *
	 * @return	PDFFORM_NOTAVAIL means the form data is not available.
	 *			PDFFORM_AVAIL means the form data is available.
	 *			PDFFORM_NOTEXIST means the form is not exist.
	 */
	virtual FX_INT32			IsFormAvail(IFX_DownloadHints *pHints);

	/** 
	 * Check whether the PDF file is linearized file.
	 * 
	 * @return The state.	PDF_IS_LINEARIZED is a linearize file.
	 *						PDF_NOT_LINEARIZED is not a linearize file.
	 *						PDF_UNKNOW_LINEARIZED don't know whether the file is a linearize file.
	 */
	virtual FX_INT32			IsLinearizedPDF();

	/** 
	 * Whether the document is Linearized PDF file.
	 * Add this function is order to quickly display the first page of the linearized file.
	 * It must be called after IPDF_DataAvailability::IsDocAvail(). When this function return TRUE, 
	 * application must calls IPDF_DataAvailability::GetLinearizedMainXRefInfo(). 
	 *
	 * @return TRUE means the document is linearized PDF else not.
	 */
	virtual FX_BOOL				IsLinearized() {return m_bLinearized;}

	/** 
	 * Get the linearized main cross-reference table position and size.
	 * When the file is linearized file. First application should get the linearized main cross-reference table position and size.
	 * Then application may create a thread to download the segment's content. If this segment's content doesn't download.
	 * The application access the page index which is not the document start page index, the IPDF_DataAvailability::IsPageAvail() 
	 * will always return FALSE.
	 *
	 * @param[out] pPos			The main cross-reference table position.
	 * @param[out] pSize		The main cross-reference table size.
	 */
	virtual void				GetLinearizedMainXRefInfo(FX_FILESIZE *pPos, FX_DWORD *pSize);

	IFX_FileRead*				GetFileRead() const { return m_pFileRead; }
	IFX_FileAvail*				GetFileAvail() const { return m_pFileAvail; }

protected:
	FX_DWORD					GetObjectSize(FX_DWORD objnum, FX_FILESIZE& offset);
	FX_BOOL						IsObjectsAvail(CFX_PtrArray& obj_array, FX_BOOL bParsePage, IFX_DownloadHints* pHints, CFX_PtrArray &ret_array);
	FX_BOOL						CheckDocStatus(IFX_DownloadHints *pHints);

	FX_BOOL						CheckHeader(IFX_DownloadHints* pHints);
	FX_BOOL						CheckFirstPage(IFX_DownloadHints *pHints);
	FX_BOOL						CheckEnd(IFX_DownloadHints *pHints);
	FX_BOOL						CheckCrossRef(IFX_DownloadHints* pHints);
	FX_BOOL						CheckCrossRefItem(IFX_DownloadHints *pHints);
	FX_BOOL						CheckTrailer(IFX_DownloadHints* pHints);
	FX_BOOL						CheckRoot(IFX_DownloadHints* pHints);
	FX_BOOL						CheckInfo(IFX_DownloadHints* pHints);
	FX_BOOL						CheckPages(IFX_DownloadHints* pHints);
	FX_BOOL						CheckPage(IFX_DownloadHints* pHints);
	FX_BOOL						CheckResources(IFX_DownloadHints* pHints);
	FX_BOOL						CheckAnnots(IFX_DownloadHints* pHints);
	FX_BOOL						CheckAcroForm(IFX_DownloadHints* pHints);
	FX_BOOL						CheckAcroFormSubObject(IFX_DownloadHints* pHints);
	FX_BOOL						CheckTrailerAppend(IFX_DownloadHints* pHints);
	FX_BOOL						CheckPageStatus(IFX_DownloadHints* pHints);
	FX_BOOL						CheckAllCrossRefStream(IFX_DownloadHints *pHints);

	/** Check the Cross reference stream. 
	 * @return -1 means not a cross reference stream, 0 need recheck. 1 is a cross reference stream.
	 */
	FX_DWORD					CheckCrossRefStream(IFX_DownloadHints *pHints, FX_FILESIZE &xref_offset);

	FX_BOOL						IsLinearizedFile(FX_LPBYTE pData, FX_DWORD dwLen);
	void						SetStartOffset(FX_FILESIZE dwOffset);
	FX_BOOL						GetNextToken(CFX_ByteString &token);
	FX_BOOL						GetNextChar(FX_BYTE &ch);
	CPDF_Object	*				ParseIndirectObjectAt(FX_FILESIZE pos, FX_DWORD objnum);
	CPDF_Object	*				GetObject(FX_DWORD objnum, IFX_DownloadHints* pHints, FX_BOOL *pExistInFile);
	FX_BOOL						GetPageKids(CPDF_Parser *pParser, CPDF_Object *pPages);
	FX_BOOL						PreparePageItem();

	FX_BOOL						LoadPages(IFX_DownloadHints* pHints);
	FX_BOOL						LoadAllXref(IFX_DownloadHints* pHints);
	FX_BOOL						LoadAllFile(IFX_DownloadHints* pHints);
	//void						LoadAnnots(int iPage);

	FX_BOOL						CheckLinearizedData(IFX_DownloadHints* pHints);
	FX_BOOL						CheckFileResources(IFX_DownloadHints* pHints);
	FX_BOOL						CheckPageAnnots(int iPage, IFX_DownloadHints* pHints);
	
	FX_BOOL						CheckLinearizedFirstPage(int iPage, IFX_DownloadHints* pHints);

	FX_BOOL						HaveResourceAncestor(CPDF_Dictionary *pDict);

	FX_BOOL						CheckPage(FX_INT32 iPage, IFX_DownloadHints* pHints);
	FX_BOOL						LoadDocPages(IFX_DownloadHints* pHints);
	FX_BOOL						LoadDocPage(FX_INT32 iPage, IFX_DownloadHints* pHints);
	FX_BOOL						CheckPageNode(CPDF_PageNode &pageNodes, FX_INT32 iPage, FX_INT32 &iCount, IFX_DownloadHints* pHints);
	FX_BOOL						CheckUnkownPageNode(FX_DWORD dwPageNo, CPDF_PageNode *pPageNode, IFX_DownloadHints* pHints);
	FX_BOOL						CheckArrayPageNode(FX_DWORD dwPageNo, CPDF_PageNode *pPageNode, IFX_DownloadHints* pHints);
    FX_BOOL                     CheckPageCount(IFX_DownloadHints* pHints);

	FX_BOOL						IsFirstCheck(int iPage);
	void						ResetFirstCheck(int iPage);

	/** The PDF parser. */
	CPDF_Parser				m_parser;
	/** The PDF syntax parser. */
	CPDF_SyntaxParser		m_syntaxParser;
	/** The Root object. */
	CPDF_Object				*m_pRoot;
	/** The Root offset. */
	FX_DWORD				m_dwRootObjNum;
	/**  The Info object num. */
	FX_DWORD				m_dwInfoObjNum;
	/** The Linearized PDF Parameter Dictionary object. */
	CPDF_Object				*m_pLinearized;
	/** The trailer pointer. */
	CPDF_Object				*m_pTrailer;
	/** Whether the document is avail. */
	FX_BOOL					m_bDocAvail;
	/** The header offset. */
	FX_FILESIZE				m_dwHeaderOffset;
	/** The last cross reference offset. */
	FX_FILESIZE				m_dwLastXRefOffset;
	/** The cross reference offset. */
	FX_FILESIZE				m_dwXRefOffset;
	/** The trailer offset. */
	FX_FILESIZE				m_dwTrailerOffset;
	/** The current offset. */
	FX_FILESIZE				m_dwCurrentOffset;
	/** The status of the parse. */
	PDF_DATAAVAIL_STATUS	m_docStatus;
	/** The file availability pointer. */
	IFX_FileAvail*			m_pFileAvail;
	/** The file read pointer. */
	IFX_FileRead*			m_pFileRead;
	/** The file length. */
	FX_FILESIZE				m_dwFileLen;			
	/** The PDF document. */
	CPDF_Document*			m_pDocument;
	/** The PDF object's number array. */
	CPDF_SortObjNumArray	m_objnum_array;
	/** The PDF object's intermediate result. */
	CFX_PtrArray			m_objs_array;
	/** The current position. */
	FX_FILESIZE				m_Pos;
	/** The cache start offset. */
	FX_FILESIZE				m_bufferOffset;
	/** The cache size. */
	FX_DWORD				m_bufferSize;
	/** The word buffer. */
	CFX_ByteString			m_WordBuf;
	/** The word buffer. we assume the max size of word is 256. */
	FX_BYTE					m_WordBuffer[257];
	/** The current word size. */
	FX_DWORD				m_WordSize;
	/** The cache data. */
	FX_BYTE					m_bufferData[512];
	/** The cross-reference tables offset. */
	CFX_FileSizeArray		m_CrossOffset;
	/** The cross-reference stream list. */
	CFX_DWordArray			m_XRefStreamList;
	/** The page object array. */
	CFX_DWordArray			m_PageObjList;
	/** The catalog pages entry offset. */
	FX_DWORD				m_PagesObjNum;
	/** Whether the PDF file is linearized. */
	FX_BOOL					m_bLinearized;
	/** The linearized PDF file first page. */
	FX_DWORD				m_dwFirstPageNo;
	/** Whether the linearized PDF data is loaded. */
	FX_BOOL					m_bLinearedDataOK;
	/** Whether the main cross-reference is loaded. */
	FX_BOOL					m_bMainXRefLoad;
	/** Whether the main cross-reference is right load. */
	FX_BOOL					m_bMainXRefLoadedOK;
	/** Whether the linearized pages tree is prepared. */
	FX_BOOL					m_bPagesTreeLoad;
	/** Whether the linearized pages is loaded. */
	FX_BOOL					m_bPagesLoad;
	/** The current parser. */
	CPDF_Parser *			m_pCurrentParser;
	/** The current xref stream offset. */
	FX_FILESIZE				m_dwCurrentXRefSteam;
	/** Whether the annots loaded. */
	FX_BOOL					m_bAnnotsLoad;
	/** Whether have acroform object. */
	FX_BOOL					m_bHaveAcroForm;
	/** The acroform object num. */
	FX_DWORD				m_dwAcroFormObjNum;
	/** Whether the acroform load. */
	FX_BOOL					m_bAcroFormLoad;
	/** The acroform object. */
	CPDF_Object	*			m_pAcroForm;
	/** The acroform subobjects. */
	CFX_PtrArray			m_arrayAcroforms;
	/** The pointer cache the page dictionary. */
	CPDF_Dictionary *		m_pPageDict;
	/** The pointer cache the page resource pointer When need download. */
	CPDF_Object *			m_pPageResource;
	/** Whether need download page resource. */
	FX_BOOL					m_bNeedDownLoadResource;
	/** The page is loaded ok. */
	FX_BOOL					m_bPageLoadedOK;
	/** Whether the linearized form parameters load.*/
	FX_BOOL					m_bLinearizedFormParamLoad;
	/** The pages array. */
	CFX_PtrArray			m_PagesArray;
	/** The encrypt object number. */
	FX_DWORD				m_dwEncryptObjNum;
	/** Whether prev cross-reference table offset. */
	FX_FILESIZE				m_dwPrevXRefOffset;
	/** Whether total load the page tree. */
	FX_BOOL					m_bTotalLoadPageTree;
	/** Whether the current page dictionary load ok. */
	FX_BOOL					m_bCurPageDictLoadOK;
	/** The page tree. */
	CPDF_PageNode			m_pageNodes;
	/** The page first check. */
	CFX_CMapDWordToDWord *	m_pageMapCheckState;
	/** The page load state. */
	CFX_CMapDWordToDWord *	m_pagesLoadState;
};

//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
class CPDF_AttachmentAcc : public CFX_Object
{
public:
	CPDF_AttachmentAcc(CPDF_Parser* pParser);

	/** 
	 * Load the attachment stream with object number.
	 * It will return PDFPARSE_ERROR_XXX, and -1 if can't find the stream.
	 */
	FX_DWORD			LoadStream(FX_DWORD objnum);
	CPDF_Stream*		GetStream() { return m_pStream; }

protected:
	FX_DWORD			InitCryptoHandler(CPDF_Stream* pStream);

	CPDF_Parser*		m_pParser;
	CPDF_Stream*		m_pStream;
};
//<<<+++OPENSOURCE_END
/*@}*/
//<<<+++OPENSOURCE_MUST_BEGIN
#endif
//<<<+++OPENSOURCE_MUST_END
/** @} */
